<?php

namespace App\Services;

use App\Repositories\BoothRepository;
use App\ResponseHandler\Response;
use Illuminate\Http\Response as LaravelResponse;
use App\Validations\Validation;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use DateTime;
use DateTimeZone;
use Symfony\Component\HttpFoundation\Response as HttpFoundationResponse;

class BoothService
{
    protected $boothRepository;
    protected $response;
    protected $validation;


    public function __construct(
        BoothRepository $boothRepository,
        Response $response,
        Validation $validation
    ) {
        $this->boothRepository = $boothRepository;
        $this->response = $response;
        $this->validation = $validation;
    }

    // Create Booth
    public function createBooth(array $data)
    {
        // Validate the booth data (you can add validation logic here)
        $validationResponse = $this->validation->validationForBooth($data);
        $responseData = $validationResponse->getData();

        if ($responseData->status !== 200) {
            return $this->response->respondWithError($responseData->message, $responseData->status);
        }
        $existingBooth = $this->boothRepository->getByBoothNumber($data['booth_number']);
        if ($existingBooth) {
            return $this->response->respondWithError('Booth number already exists', 409); // 409 Conflict
        }

        $booth = $this->boothRepository->create([
            'booth_number' => $data['booth_number'],
            'booth_address' => $data['booth_address'],
            'streets' => $data['streets'] ?? null,
            'ward_no' => isset($data['ward_no']) ? $data['ward_no'] : null,
            'h1' => isset($data['h1']) ? $data['h1'] : null,
            'h2' => isset($data['h2']) ? $data['h2'] : null,
        ]);

        // Defensive: ensure optional hierarchy fields are persisted even if create didn't pick them up
        if ($booth) {
            $changed = false;
            if (isset($data['ward_no']) && $booth->ward_no != $data['ward_no']) {
                $booth->ward_no = $data['ward_no'];
                $changed = true;
            }
            if (isset($data['h1']) && $booth->h1 != $data['h1']) {
                $booth->h1 = $data['h1'];
                $changed = true;
            }
            if (isset($data['h2']) && $booth->h2 != $data['h2']) {
                $booth->h2 = $data['h2'];
                $changed = true;
            }

            if ($changed) {
                try {
                    $booth->save();
                } catch (\Exception $e) {
                    // Log and continue; respond with created booth anyway
                    // If logging facility available, you can log: \Log::error('Booth save h1/h2 failed', ['err' => $e->getMessage()]);
                }
            }
        }

        return $booth
            ? $this->response->respondWithData('Booth created successfully', $booth, new LaravelResponse)
            : $this->response->respondWithError('Error creating Booth.');
    }

    // Update Booth
    public function updateBooth($boothId, array $data)
    {
        // Get the original booth before updating to check if booth_number is changing
        $originalBooth = \App\Models\Booth::find($boothId);
        
        if (!$originalBooth) {
            return $this->response->respondWithError('Booth not found', 404);
        }

        $originalBoothNumber = $originalBooth->booth_number;

        // Check if the booth exists and then update
        $booth = $this->boothRepository->update($boothId, $data);

        if (!$booth) {
            return $this->response->respondWithError('Something went wrong', 404); // 404 Not Found
        }

        // If booth_number was updated, cascade the change to voters table
        if (isset($data['booth_number']) && $data['booth_number'] !== $originalBoothNumber) {
            \App\Models\Voter::where('booth_number', $originalBoothNumber)
                ->where('is_deleted', false)
                ->update(['booth_number' => $data['booth_number']]);
        }

        return $this->response->respondWithData('Booth updated successfully', $booth, new LaravelResponse());
    }

    // Get all Booths and Count
    public function getAllBooths()
    {
        $booths = $this->boothRepository->getAll();
        $boothCount = $this->boothRepository->getBoothCount();

        // Add voters_count to each booth
        $boothsWithVotersCount = $booths->map(function ($booth) {
            $votersCount = \App\Models\Voter::where('booth_number', $booth->booth_number)
                                           ->where('is_deleted', false)
                                           ->count();

            $mappedVotersCount = \App\Models\Voter::where('booth_number', $booth->booth_number)
                                                    ->where('is_deleted', false)
                                                    ->whereNotNull('ration_card_id')
                                                    ->count();
            
            $rationCardCount = \App\Models\RationCard::whereHas('voters', function($query) use ($booth) {
                $query->where('booth_number', $booth->booth_number)
                      ->where('is_deleted', false);
            })->where('is_deleted', false)->count();
            
            $unmappedVotersCount = \App\Models\Voter::where('booth_number', $booth->booth_number)
                                                    ->where('is_deleted', false)
                                                    ->whereNull('ration_card_id')
                                                    ->count();
            
            // Convert booth to array and add voters_count
            $boothArray = $booth->toArray();
            $boothArray['voters_count'] = $votersCount;
            $boothArray['mapped_voters_count'] = $mappedVotersCount;
            $boothArray['rationcard_count'] = $rationCardCount;
            $boothArray['unmapped_voters_count'] = $unmappedVotersCount;
            
            return $boothArray;
        });

        // Collect unique, non-empty h1 and h2 values across booths
        try {
            $h1List = $booths->pluck('h1')
                            ->filter(function ($v) { return $v !== null && $v !== ''; })
                            ->unique()
                            ->values()
                            ->all();

            $h2List = $booths->pluck('h2')
                            ->filter(function ($v) { return $v !== null && $v !== ''; })
                            ->unique()
                            ->values()
                            ->all();
        } catch (\Exception $e) {
            $h1List = [];
            $h2List = [];
        }

        return response()->json([
            'status' => 200,
            'message' => 'Booths fetched successfully',
            'data' => $boothsWithVotersCount,
            'count' => $boothCount,
            'h1_list' => $h1List,
            'h2_list' => $h2List,
        ]);
    }

    /**
     * Get booths along with streets, categories and castes in one response
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function getBoothsWithLists()
    {
        $booths = $this->boothRepository->getAll();
        $boothCount = $this->boothRepository->getBoothCount();

        $boothsWithVotersCount = $booths->map(function ($booth) {
            $votersCount = \App\Models\Voter::where('booth_number', $booth->booth_number)
                                           ->where('is_deleted', false)
                                           ->count();

            $rationCardCount = \App\Models\RationCard::whereHas('voters', function($query) use ($booth) {
                $query->where('booth_number', $booth->booth_number)
                      ->where('is_deleted', false);
            })->where('is_deleted', false)->count();

            $boothArray = $booth->toArray();
            $boothArray['voters_count'] = $votersCount;
            $boothArray['rationcard_count'] = $rationCardCount;
            return $boothArray;
        });

        $booths = \App\Models\Booth::where('is_deleted', false)
                ->select('id', 'booth_number', 'booth_address')
                ->orderBy('booth_number')
                ->get();

        $categories = \App\Models\Category::select('id', 'name')->orderBy('name')->get();
        $castes = \App\Models\Caste::select('id', 'name')->orderBy('name')->get();

        $responsePayload = [
            'booths' => $boothsWithVotersCount,
            'count' => $boothCount,
            'categories' => $categories,
            'castes' => $castes,
        ];

        return $this->response->respondWithData('Booths, categories and castes fetched successfully', $responsePayload, new LaravelResponse());
    }

    /**
     * Return static lists used in forms: streets, categories, castes, genders
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function getStaticList()
    {
        // Fetch booths and compute voters_count + expand streets similar to getAllBooths
        $booths = $this->boothRepository->getAll();
        $boothCount = $this->boothRepository->getBoothCount();

        $boothsWithVotersCount = $booths->map(function ($booth) {
            $votersCount = \App\Models\Voter::where('booth_number', $booth->booth_number)
                                           ->where('is_deleted', false)
                                           ->count();

            $rationCardCount = \App\Models\RationCard::whereHas('voters', function($query) use ($booth) {
                $query->where('booth_number', $booth->booth_number)
                      ->where('is_deleted', false);
            })->where('is_deleted', false)->count();

            $boothArray = $booth->toArray();
            $boothArray['voters_count'] = $votersCount;
            $boothArray['rationcard_count'] = $rationCardCount;

            // Resolve street models if available
            try {
                $streetModels = method_exists($booth, 'getStreetModelsAttribute') ? $booth->getStreetModelsAttribute() : collect();
                $boothArray['streets'] = $streetModels->map(function ($s) {
                    return [
                        'id' => $s->id,
                        'name' => $s->street_name,
                    ];
                })->values();
            } catch (\Exception $e) {
                $boothArray['streets'] = $boothArray['streets'] ?? null;
            }

            return $boothArray;
        });

        $categories = \App\Models\Category::select('id', 'name')->orderBy('name')->get();
        $castes = \App\Models\Caste::select('id', 'name')->orderBy('name')->get();

        $payload = [
            'booths' => $boothsWithVotersCount,
            'count' => $boothCount,
            'categories' => $categories,
            'castes' => $castes,
        ];

        return $this->response->respondWithData('Static lists fetched successfully', $payload, new LaravelResponse());
    }

    // Get Single Booth by ID
    public function getBoothById($boothId)
    {
        $booth = $this->boothRepository->getById($boothId);
        
        if (!$booth) {
            return $this->response->respondWithError('Booth not found', 404);
        }

        // Add voters_count to the booth
        $votersCount = \App\Models\Voter::where('booth_number', $booth->booth_number)
                                       ->where('is_deleted', false)
                                       ->count();
        
        $rationCardCount = \App\Models\RationCard::whereHas('voters', function($query) use ($booth) {
            $query->where('booth_number', $booth->booth_number)
                  ->where('is_deleted', false);
        })->where('is_deleted', false)->count();
        
        $boothArray = $booth->toArray();
        $boothArray['voters_count'] = $votersCount;
        $boothArray['rationcard_count'] = $rationCardCount;

        return response()->json([
            'status' => 200,
            'message' => 'Booth fetched successfully',
            'data' => $boothArray,
        ]);
    }

    // Soft Delete Booth
    public function deleteBooth($boothNumber)
    {
        if (empty($boothNumber)) {
            return $this->response->respondWithError('Booth number is required');
        }

        $deleted = $this->boothRepository->delete($boothNumber);

        if ($deleted) {
            return $this->response->respondWithData('Booth deleted successfully', null, new \Illuminate\Http\Response);
        }

        return $this->response->respondWithError('Booth not found or already deleted', 404);
    }

 // Method to get the booth count
    public function getBoothCount()
    {
        return $this->boothRepository->getBoothCount();
    }

    public function downloadAsExcel()
    {
        $boothList =  $this->boothRepository->getAll();
        
        // Check if booth list is empty
        if ($boothList->isEmpty()) {
            return $this->response->respondWithError('Booth list is empty, So unable to generate excel document', 404);
        }
        
        $folderName = 'EXCEL_SHEETS';

        $excelUploadDirectory = env('FILE_UPLOAD_DIRECTORY') . $folderName;

        if (!file_exists($excelUploadDirectory)) {
            mkdir($excelUploadDirectory, 0777, true);
        }


        $headers = [
            'Booth Number',
            'Booth Address'
        ];

        

        // Create a new Spreadsheet object
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        $sheet->setTitle(strtolower('Test'));

        $sheet->setCellValue('A1', 'Serial No.');
        $sheet->getStyle('A1')
            ->getFont()
            ->setBold(true);

        // Set headers
        $col = 'B';
        foreach ($headers as $header) {
            $sheet->setCellValue($col . '1', $header);

            $sheet->getStyle($col . '1')
                ->getFont()
                ->setBold(true);
            $sheet->getStyle($col . '1')
                ->getAlignment()
                ->setHorizontal(Alignment::HORIZONTAL_CENTER);
            $sheet->getColumnDimension($col)->setAutoSize(true);

            $col++;
        }

        $row = 2;
        $serialNumber = 1;
        foreach ($boothList as $booth) {
            $excelValues = [
                $booth->booth_number,
                $booth->booth_address
             ];

            $col = 'A';
            $sheet->setCellValue($col . $row, $serialNumber); // Set serial number
            $serialNumber++;
            $sheet->getStyle($col . $row)
                ->getAlignment()
                ->setHorizontal(Alignment::HORIZONTAL_CENTER);

            $col = 'B'; // Start from column B for actual data
            foreach ($excelValues as $value) {
                $sheet->setCellValue($col . $row, $value);

                // Set the column width to auto-size
                $sheet->getColumnDimension($col)->setAutoSize(true);

                // Set the alignment to center
                $sheet->getStyle($col . $row)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
                $sheet->getStyle($col . $row)->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER); // Optional: vertical centering

                $col++;
            }

            $row++;
        }

        $date = new DateTime('now', new DateTimeZone('Asia/Kolkata'));

        $writer = new Xlsx($spreadsheet);
        $dateTime = $date->format('Y-m-d_H-i-s');

        $excelFileName = 'booths-' . $dateTime . '.xlsx';
        $excelFilePath = $excelUploadDirectory . DIRECTORY_SEPARATOR . $excelFileName;

        if (!is_writable($excelUploadDirectory)) {
            return $this->response->respondWithError('Unable to write to the directory: ' . $excelFilePath);
        }

        $writer->save($excelFilePath);

        // return $this->response->respondWithData('Excel generated Successfully', $folderName . DIRECTORY_SEPARATOR . $excelFileName, new LaravelResponse);

        $fileContent = file_get_contents($excelFilePath);

        // Create response with headers for content type and content disposition
        $response = new HttpFoundationResponse($fileContent);
        $response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        $response->headers->set('Content-Disposition', 'attachment; filename="' . $excelFileName . '"');

        // You can also set other headers if needed (e.g., cache control)
        $response->headers->set('Cache-Control', 'no-store, no-cache, must-revalidate');
        $response->headers->set('Pragma', 'no-cache');
        $response->headers->set('Expires', '0');

        return $response;
    }

    
}
