<?php
namespace App\Services;

use App\Repositories\GiftRepository;
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\StreamedResponse;

class GiftService
{
    protected $giftRepository;
    protected $response;
    protected $validation;

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

    // Create Gift
    public function createGift($data)
    {

     // Validate the gift data (you can add validation logic here)
        $validationResponse = $this->validation->validateGiftData($data);
        $responseData = $validationResponse->getData();

        if ($responseData->status !== 200) {
            return $this->response->respondWithError($responseData->message, $responseData->status);
        }

      

        // Create the gift
        $gift = $this->giftRepository->createGift([
            'gift_name' => $data['gift_name']
        ]);

        // Return response based on success or failure
        return $gift
            ? $this->response->respondWithData('Gift created successfully', $gift, new LaravelResponse)
            : $this->response->respondWithError('Error creating Gift.');

    }

    // Get Gift by ID
    public function getGiftById($id)
    {
        $gift = $this->giftRepository->getGiftById($id);

        return $gift
            ? $this->response->respondWithData('Retrieved successfully.', $gift, new LaravelResponse)
            : $this->response->respondWithError('No gift found.');
    }

    // Get all active Gifts
    public function getAllGifts()
    {
        $gifts = $this->giftRepository->getAllGifts();

        if (empty($gifts)) {
            return $this->response->respondWithError('No gifts found.');
        }

        // Add gifted_count and pending_count to each gift
        $giftsWithCounts = collect($gifts)->map(function ($gift) {
            // Convert gift to array
            $giftArray = $gift->toArray();
            
            // Calculate gifted_count: Count of ration cards that received this gift
            $giftedCount = \App\Models\GiftedRationCard::where('gift_id', $gift->id)
                                                      ->where('is_deleted', false)
                                                      ->count();
            
            // Calculate pending_count: Total ration cards - ration cards that received this gift
            $totalRationCards = \App\Models\RationCard::where('is_deleted', false)->count();
            $pendingCount = $totalRationCards - $giftedCount;
            
            // Add counts to gift array
            $giftArray['gifted_count'] = $giftedCount;
            $giftArray['pending_count'] = $pendingCount;
            
            return $giftArray;
        });

        return $this->response->respondWithData('Retrieved successfully.', $giftsWithCounts, new LaravelResponse);
    }

    // Get all deleted Gifts
    public function getAllDeletedGifts()
    {
        $deletedGifts = $this->giftRepository->getAllDeletedGifts();

        return $deletedGifts->isEmpty()
            ? $this->response->respondWithError('No deleted gifts found.')
            : $this->response->respondWithData('Retrieved Successfully.', $deletedGifts, new LaravelResponse);
    }

    // Update Gift by ID
    public function updateGiftById($id, array $data)
    {
        $existingGift = $this->giftRepository->findGiftById($id);

        if (!$existingGift) {
            return $this->response->respondWithError('No gift found.');
        }

        $updatedGift = $this->giftRepository->updateGiftById($id, $data);

        return $updatedGift == 1
            ? $this->response->respondWithData('Gift updated successfully.', $this->giftRepository->findGiftById($id), new LaravelResponse)
            : $this->response->respondWithError('Error while updating Gift.');
    }

    // Soft delete Gift by ID
    public function deleteGiftById($id)
    {
        $existingGift = $this->giftRepository->findGiftById($id);

        if (!$existingGift) {
            return $this->response->respondWithError('No gift found.');
        }

        $result = $this->giftRepository->deleteGiftById($id);

        return $result
            ? $this->response->respondWithData('Gift deleted successfully', null, new LaravelResponse)
            : $this->response->respondWithError('Error while deleting Gift.');
    }

    /**
     * Distribute gifts to ration cards with validation
     */
    public function distributeGift($data)
    {
        $giftId = $data['gift_number'] ?? null;
        $rationCardNumbers = $data['ration_card_number'] ?? [];

        // Validate basic input
        if (!$giftId || empty($rationCardNumbers) || !is_array($rationCardNumbers)) {
            return $this->response->respondWithError('Invalid request data. Gift number and ration card numbers are required.', 400);
        }

        // Check if gift exists
        $gift = $this->giftRepository->findGiftById($giftId);
        if (!$gift) {
            return $this->response->respondWithError('Gift not found with ID: ' . $giftId, 404);
        }

        $invalidRationCards = [];
        $alreadyDistributed = [];
        $validRationCards = [];

        foreach ($rationCardNumbers as $rationCardNumber) {
            // Validation 1: Check if ration card exists and is not deleted
            $rationCard = \App\Models\RationCard::where('ration_card_number', $rationCardNumber)
                                                ->where('is_deleted', false)
                                                ->first();
            
            if (!$rationCard) {
                $invalidRationCards[] = $rationCardNumber;
                continue;
            }

            // Validation 2: Check if gift is already distributed to this ration card
            if (\App\Models\GiftedRationCard::isAlreadyDistributed($giftId, $rationCardNumber)) {
                $alreadyDistributed[] = $rationCardNumber;
                continue;
            }

            // Valid ration card
            $validRationCards[] = $rationCardNumber;
        }

        // Save valid records
        $savedCount = 0;
        foreach ($validRationCards as $rationCardNumber) {
            $giftedRationCard = \App\Models\GiftedRationCard::create([
                'gift_id' => $giftId,
                'ration_card_number' => $rationCardNumber,
                'is_deleted' => false
            ]);
            
            if ($giftedRationCard) {
                $savedCount++;
            }
        }

        // Prepare response
        $responseData = [
            'successfully_distributed' => $savedCount,
            'total_requested' => count($rationCardNumbers),
            'gift_name' => $gift->gift_name,
            'gift_id' => $giftId
        ];

        // Add validation errors if any
        if (!empty($invalidRationCards) || !empty($alreadyDistributed)) {
            $responseData['validation_errors'] = [];
            
            if (!empty($invalidRationCards)) {
                $responseData['validation_errors']['invalidRationCards'] = $invalidRationCards;
            }
            
            if (!empty($alreadyDistributed)) {
                $responseData['validation_errors']['alreadyDistributed'] = $alreadyDistributed;
            }
        }

        return $this->response->respondWithData(
            'Gift distribution completed successfully', 
            $responseData, 
            new LaravelResponse
        );
    }


public function distributeSinleGift($data)
{
    $giftId = $data['gift_number'] ?? null;
    $rationCardNumber = $data['ration_card_number'] ?? null; // now single only

    if (!$giftId || !$rationCardNumber) {
        return $this->response->respondWithError('Gift number and ration card number are required.', 400);
    }

    // Check if gift exists
    $gift = $this->giftRepository->findGiftById($giftId);
    if (!$gift) {
        return $this->response->respondWithError('Gift not found with ID: ' . $giftId, 404);
    }

    // Check if ration card exists
    $rationCard = \App\Models\RationCard::where('ration_card_number', $rationCardNumber)
                                        ->where('is_deleted', false)
                                        ->first();
    if (!$rationCard) {
        return $this->response->respondWithError('Invalid ration card number: ' . $rationCardNumber, 404);
    }

    // Check if gift already distributed
    if (\App\Models\GiftedRationCard::isAlreadyDistributed($giftId, $rationCardNumber)) {
        // Fetch the active gifted record to obtain the actual distribution timestamp
        $existingGifted = \App\Models\GiftedRationCard::where('gift_id', $giftId)
            ->where('ration_card_number', $rationCardNumber)
            ->where('is_deleted', false)
            ->orderBy('updated_at', 'desc')
            ->first();

        if ($existingGifted && $existingGifted->updated_at) {
            $dateTime = $existingGifted->updated_at->setTimezone('Asia/Kolkata')->format('d-m-Y H:i:s');
        } else {
            $dateTime = (new DateTime('now', new DateTimeZone('Asia/Kolkata')))->format('d-m-Y H:i:s');
        }

        return $this->response->respondWithError('Gift already distributed to this ration card. ' . $dateTime, 409);
    }

    // Insert record
    \App\Models\GiftedRationCard::create([
        'gift_id' => $giftId,
        'ration_card_number' => $rationCardNumber,
        'is_deleted' => false
    ]);

    return $this->response->respondWithData(
        'Gift successfully distributed to ration card.',
        [
            'gift_name' => $gift->gift_name,
            'gift_id' => $giftId,
            'ration_card_number' => $rationCardNumber
        ],
        new LaravelResponse
    );
}

    /**
     * Revert gift distribution for a ration card
     */
    public function revertGiftDistribution($data)
    {
        $giftId = $data['gift_id'] ?? $data['gift_number'] ?? null;
        $rationCardNumber = $data['ration_card_number'] ?? null;

        if (!$giftId || !$rationCardNumber) {
            return $this->response->respondWithError('Gift ID and ration card number are required.', 400);
        }

        // Check if gift exists
        $gift = $this->giftRepository->findGiftById($giftId);
        if (!$gift) {
            return $this->response->respondWithError('Gift not found with ID: ' . $giftId, 404);
        }

        // Check if ration card exists
        $rationCard = \App\Models\RationCard::where('ration_card_number', $rationCardNumber)
                                            ->where('is_deleted', false)
                                            ->first();
        if (!$rationCard) {
            return $this->response->respondWithError('Invalid ration card number: ' . $rationCardNumber, 404);
        }

        // Check if gift distribution exists (active)
        $giftedRationCard = \App\Models\GiftedRationCard::where('gift_id', $giftId)
            ->where('ration_card_number', $rationCardNumber)
            ->where('is_deleted', false)
            ->first();

        // Check if a deleted record already exists (prevents unique constraint violation)
        $deletedRecordExists = \App\Models\GiftedRationCard::where('gift_id', $giftId)
            ->where('ration_card_number', $rationCardNumber)
            ->where('is_deleted', true)
            ->exists();

        if (!$giftedRationCard) {
            return $this->response->respondWithError('No active gift distribution found to revert for this ration card.', 404);
        }

        if ($deletedRecordExists) {
            // If a deleted record already exists, hard delete the active one to avoid duplicate unique key
            $giftedRationCard->delete();
        } else {
            // Soft delete the distribution record
            $giftedRationCard->is_deleted = true;
            $giftedRationCard->save();
        }

        $dateTime = (new DateTime('now', new DateTimeZone('Asia/Kolkata')))->format('d-m-Y H:i:s');

        return $this->response->respondWithData(
            'Gift distribution reverted successfully.',
            [
                'gift_name' => $gift->gift_name,
                'gift_id' => $giftId,
                'ration_card_number' => $rationCardNumber,
                'reverted_at' => $dateTime
            ],
            new LaravelResponse
        );
    }

    /**
     * Download gift distribution report as Excel
     * @param int $giftId - The gift ID
     * @param bool $gifted - true for gifted cards, false for pending cards
     */
    public function downloadGiftDistributionExcel($giftId, $gifted)
    {
        // Check if gift exists
        $gift = $this->giftRepository->findGiftById($giftId);
        if (!$gift) {
            return $this->response->respondWithError('Gift not found with ID: ' . $giftId, 404);
        }

        // Configuration for large dataset handling
        $chunkSize = 1000;
        $maxMemory = '256M';
        $maxExecutionTime = 600;
        
        ini_set('memory_limit', $maxMemory);
        ini_set('max_execution_time', $maxExecutionTime);

        $date = new DateTime('now', new DateTimeZone('Asia/Kolkata'));
        $dateTime = $date->format('Y-m-d_H-i-s');
        $status = $gifted ? 'gifted' : 'pending';
        $excelFileName = "gift-{$giftId}-{$status}-{$dateTime}.xlsx";

        // Get distributed ration card numbers for this gift
        $distributedRationCards = \App\Models\GiftedRationCard::getDistributedRationCards($giftId);

        // Use StreamedResponse for memory efficiency
        return new StreamedResponse(function () use ($chunkSize, $excelFileName, $giftId, $gifted, $gift, $distributedRationCards) {
            // Create Excel file
            $spreadsheet = new Spreadsheet();
            $sheet = $spreadsheet->getActiveSheet();
            $sheetTitle = $gifted ? 'Gifted RationCards' : 'Pending RationCards';
            $sheet->setTitle($sheetTitle);

            // Set headers - same as RationCardService downloadAsExcel
            $headers = [
                'Serial No.',
                'RationCard Number', 
                'RationCard Address',
                'Head Name',
                'Head Phone Number',
                'Other State'
            ];

            // Write headers
            $col = 'A';
            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++;
            }

            $currentRow = 2;
            $serialNumber = 1;
            $hasData = false;
            
            // Query based on gifted status
            $query = \App\Models\RationCard::where('is_deleted', false)
                ->with(['voters' => function ($query) {
                    $query->where('is_head', true)->where('is_deleted', false);
                }]);

            if ($gifted) {
                // Show only ration cards that received this gift
                $query->whereIn('ration_card_number', $distributedRationCards);
            } else {
                // Show only ration cards that have NOT received this gift
                $query->whereNotIn('ration_card_number', $distributedRationCards);
            }

            // Process records in chunks to avoid memory issues
            $query->chunk($chunkSize, function ($records) use ($sheet, &$currentRow, &$serialNumber, &$hasData) {
                foreach ($records as $record) {
                    $hasData = true;
                    
                    // Get head voter info
                    $headVoter = $record->voters->first();
                    $headName = $headVoter ? $headVoter->name : 'N/A';
                    $headPhone = $headVoter ? $headVoter->mobile_number : 'N/A';

                    $rowData = [
                        $serialNumber,
                        $record->ration_card_number,
                        $record->address,
                        $headName,
                        $headPhone,
                        $record->other_state
                    ];

                    // Write row data
                    $col = 'A';
                    foreach ($rowData as $value) {
                        $sheet->setCellValue($col . $currentRow, $value);
                        $sheet->getStyle($col . $currentRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
                        $col++;
                    }

                    $currentRow++;
                    $serialNumber++;
                    
                    // Clear memory every 100 records
                    if ($serialNumber % 100 === 0) {
                        $sheet->garbageCollect();
                    }
                }
            });

            // If no data found, add a message row
            if (!$hasData) {
                $message = $gifted ? 'No ration cards have received this gift yet.' : 'All ration cards have received this gift.';
                $sheet->setCellValue('A2', $message);
                $sheet->mergeCells('A2:F2');
                $sheet->getStyle('A2')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
                $sheet->getStyle('A2')->getFont()->setItalic(true);
            }

            // Create temporary file for streaming
            $tempFile = tempnam(sys_get_temp_dir(), 'gift_distribution_export_');
            
            $writer = new Xlsx($spreadsheet);
            $writer->save($tempFile);
            
            // Stream the file
            $handle = fopen($tempFile, 'r');
            while (!feof($handle)) {
                echo fread($handle, 8192); // Read in 8KB chunks
                flush(); // Ensure data is sent immediately
            }
            fclose($handle);
            
            // Clean up temporary file
            unlink($tempFile);
            
            // Clean up spreadsheet from memory
            $spreadsheet->disconnectWorksheets();
            unset($spreadsheet);
            
        }, 200, [
            'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'Content-Disposition' => 'attachment; filename="' . $excelFileName . '"',
            'Cache-Control' => 'no-store, no-cache, must-revalidate',
            'Pragma' => 'no-cache',
            'Expires' => '0'
        ]);
    }

    /**
     * Get mobile numbers of head voters for gifted ration cards
     * @param int $giftId
     * @return array
     */
    public function getGiftedMobileNumbers($giftId)
    {
        try {
            // Check if gift exists
            $gift = $this->giftRepository->findGiftById($giftId);
            if (!$gift) {
                return [
                    'status' => 'error',
                    'message' => 'Gift not found with ID: ' . $giftId,
                    'mobile_numbers' => []
                ];
            }

            // Get distributed ration card numbers for this gift
            $distributedRationCards = \App\Models\GiftedRationCard::getDistributedRationCards($giftId);

            if (empty($distributedRationCards)) {
                return [
                    'status' => 'success',
                    'message' => 'No ration cards have received this gift yet',
                    'mobile_numbers' => []
                ];
            }

            // Get mobile numbers of head voters from gifted ration cards
            $mobileNumbers = \App\Models\RationCard::whereIn('ration_card_number', $distributedRationCards)
                ->where('is_deleted', false)
                ->where('other_state', false) // Only local state ration cards
                ->with(['voters' => function ($query) {
                    $query->where('is_head', true)
                          ->where('is_deleted', false)
                          ->whereNotNull('mobile_number')
                          ->where('mobile_number', '!=', '');
                }])
                ->get()
                ->pluck('voters')
                ->flatten()
                ->pluck('mobile_number')
                ->unique()
                ->filter()
                ->values()
                ->toArray();

            return [
                'status' => 'success',
                'message' => 'Mobile numbers retrieved successfully for gifted ration cards',
                'mobile_numbers' => $mobileNumbers,
                'count' => count($mobileNumbers),
                'gift_name' => $gift->gift_name
            ];

        } catch (\Exception $e) {
            \Log::error('Get Gifted Mobile Numbers Error', [
                'gift_id' => $giftId,
                'error' => $e->getMessage()
            ]);

            return [
                'status' => 'error',
                'message' => 'Error retrieving mobile numbers: ' . $e->getMessage(),
                'mobile_numbers' => []
            ];
        }
    }

    /**
     * Get mobile numbers of head voters for pending (non-gifted) ration cards
     * @param int $giftId
     * @return array
     */
    public function getPendingMobileNumbers($giftId)
    {
        try {
            // Check if gift exists
            $gift = $this->giftRepository->findGiftById($giftId);
            if (!$gift) {
                return [
                    'status' => 'error',
                    'message' => 'Gift not found with ID: ' . $giftId,
                    'mobile_numbers' => []
                ];
            }

            // Get distributed ration card numbers for this gift
            $distributedRationCards = \App\Models\GiftedRationCard::getDistributedRationCards($giftId);

            // Get mobile numbers of head voters from NON-gifted ration cards
            $query = \App\Models\RationCard::where('is_deleted', false)
                ->where('other_state', false); // Only local state ration cards

            if (!empty($distributedRationCards)) {
                $query->whereNotIn('ration_card_number', $distributedRationCards);
            }

            $mobileNumbers = $query->with(['voters' => function ($query) {
                    $query->where('is_head', true)
                          ->where('is_deleted', false)
                          ->whereNotNull('mobile_number')
                          ->where('mobile_number', '!=', '');
                }])
                ->get()
                ->pluck('voters')
                ->flatten()
                ->pluck('mobile_number')
                ->unique()
                ->filter()
                ->values()
                ->toArray();

            return [
                'status' => 'success',
                'message' => 'Mobile numbers retrieved successfully for pending ration cards',
                'mobile_numbers' => $mobileNumbers,
                'count' => count($mobileNumbers),
                'gift_name' => $gift->gift_name
            ];

        } catch (\Exception $e) {
            \Log::error('Get Pending Mobile Numbers Error', [
                'gift_id' => $giftId,
                'error' => $e->getMessage()
            ]);

            return [
                'status' => 'error',
                'message' => 'Error retrieving mobile numbers: ' . $e->getMessage(),
                'mobile_numbers' => []
            ];
        }
    }

    /**
     * Get all mobile numbers of head voters (for sendToAll functionality)
     * @return array
     */
    public function getAllMobileNumbers()
    {
        try {
            // Get mobile numbers of all head voters from local state ration cards
            $mobileNumbers = \App\Models\RationCard::where('is_deleted', false)
                ->where('other_state', false) // Only local state ration cards
                ->with(['voters' => function ($query) {
                    $query->where('is_head', true)
                          ->where('is_deleted', false)
                          ->whereNotNull('mobile_number')
                          ->where('mobile_number', '!=', '');
                }])
                ->get()
                ->pluck('voters')
                ->flatten()
                ->pluck('mobile_number')
                ->unique()
                ->filter()
                ->values()
                ->toArray();

            return [
                'status' => 'success',
                'message' => 'All mobile numbers retrieved successfully',
                'mobile_numbers' => $mobileNumbers,
                'count' => count($mobileNumbers)
            ];

        } catch (\Exception $e) {
            \Log::error('Get All Mobile Numbers Error', [
                'error' => $e->getMessage()
            ]);

            return [
                'status' => 'error',
                'message' => 'Error retrieving mobile numbers: ' . $e->getMessage(),
                'mobile_numbers' => []
            ];
        }
    }

    /**
     * Get gifts distributed to a specific ration card number
     */
    public function getGiftsByRationCard($rationCardNumber)
    {
        // Validate ration card number
        if (empty($rationCardNumber)) {
            return $this->response->respondWithError('Ration card number is required.', 400);
        }

        // Check if ration card exists
        $rationCard = \App\Models\RationCard::where('ration_card_number', $rationCardNumber)
                                            ->where('is_deleted', false)
                                            ->first();
        
        if (!$rationCard) {
            return $this->response->respondWithError('Ration card not found: ' . $rationCardNumber, 404);
        }

        // Get gifts distributed to this ration card
        $giftedRationCards = $this->giftRepository->getGiftsByRationCard($rationCardNumber);

        // Format the response data
        $giftsData = $giftedRationCards->map(function ($giftedRationCard) {
            return [
                'id' => $giftedRationCard->id,
                'gift_id' => $giftedRationCard->gift_id,
                'gift_name' => $giftedRationCard->gift->gift_name ?? 'Unknown Gift',
                'ration_card_number' => $giftedRationCard->ration_card_number,
                'distributed_date' => $giftedRationCard->created_at->format('Y-m-d'),
                'distributed_datetime' => $giftedRationCard->created_at->format('Y-m-d H:i:s'),
                'status' => 'Distributed'
            ];
        });

        $responseData = [
            'ration_card_number' => $rationCardNumber,
            'total_gifts_received' => $giftsData->count(),
            'gifts' => $giftsData
        ];

        $message = $giftsData->isEmpty() 
            ? 'No gifts found for ration card: ' . $rationCardNumber
            : 'Gifts retrieved successfully for ration card: ' . $rationCardNumber;

        return $this->response->respondWithData(
            $message,
            $responseData,
            new LaravelResponse
        );
    }
}
