<?php

namespace App\Http\Controllers\Eventmie;

use Facades\Classiebit\Eventmie\Eventmie;
use App\Http\Controllers\Controller; 

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Carbon\Carbon;
use Intervention\Image\Facades\Image;
use File;

use Auth;

use App\Models\Event;
use App\Models\Booking;
use App\Models\Checkin;


class TicketScannerController extends Controller
{
    public function __construct()
    {
        $this->middleware('organiser');
    }

    public function index(Request $request, $view = 'vendor.eventmie-pro.ticket_scanner.index', $extra = [])
    {
        /**
         * Event Validations
         * 1. Fetch event who end_date >= today
         * 2. If Organiser is logged in, then fetch event who user_id = logged in user_id
         * 3. If Scanner is logged in, then fetch event who user_id = logged in user_id in user_roles table
         * 4. If Admin is logged in, don't fetch any event, Admin can scan tickets for all events
         */
        
        // On the basis of logged in scanner or organiser, fetch all the event ids for which they can scan tickets for
        $allowed_event_ids = [];
        $today = Carbon::today()->format('Y-m-d');

        if (Auth::user()->hasRole('organiser')) {
            // Get events created by organiser that are not expired
            $query = Event::select('id', 'scan_on_event_day_only')
                ->where('user_id', Auth::id())
                ->where('end_date', '>=', $today);

            // Use chunk to handle large datasets
            $query->chunk(50, function($events) use (&$allowed_event_ids) {
                foreach($events as $event) {
                    $allowed_event_ids[] = [
                        'event_id' => $event->id,
                        'scan_on_event_day_only' => (bool)$event->scan_on_event_day_only
                    ];
                }
            });

            if(empty($allowed_event_ids)) {
                if ($request->expectsJson()) {
                    return response()->json([
                        'status' => false,
                        'message' => __('eventmie-pro::em.no_events_available_scanning')
                    ], 404);
                }
                return error_redirect(__('eventmie-pro::em.no_events_available_scanning'));
            }
        }
        elseif (Auth::user()->hasRole('scanner')) {
            // Get events assigned to scanner that are active today
            $query = Event::select('events.id', 'events.scan_on_event_day_only')
                ->join('user_roles', function($join) {
                    $join->on('events.id', '=', 'user_roles.event_id')
                        ->where('user_roles.user_id', Auth::id());
                })
                ->where('events.end_date', '>=', $today);

            // Use chunk to handle large datasets
            $query->chunk(50, function($events) use (&$allowed_event_ids) {
                foreach($events as $event) {
                    $allowed_event_ids[] = [
                        'event_id' => $event->id,
                        'scan_on_event_day_only' => (bool)$event->scan_on_event_day_only
                    ];
                }
            });

            if(empty($allowed_event_ids)) {
                if ($request->expectsJson()) {
                    return response()->json([
                        'status' => false,
                        'message' => __('eventmie-pro::em.no_events_assigned_active')
                    ], 404);
                }
                return error_redirect(__('eventmie-pro::em.no_events_assigned_active'));
            }
        }
        // Admin can access all events, so no need to set allowed_event_ids

        session()->put('allowed_event_ids', $allowed_event_ids);

        $extra['refresh_timer'] = 3000;

        if ($request->expectsJson()) {
            return response()->json([
                'status' => true,
                'allowed_event_ids' => $allowed_event_ids,
                'extra' => $extra
            ]);
        }

        return view($view, compact('extra'));
    }

    public function verify_and_checkin(Request $request)
    {
        $request->validate([
            'order_number' => 'required',
            'scan_all' => 'sometimes|boolean',
        ],['order_number.required' => __('eventmie-pro::em.ticket_not_found')]);

        // Fetch bookings
        $bookings = $this->getBookingsFromRequest($request);

        if ($bookings->isEmpty()) {
            $msg = __('eventmie-pro::em.ticket_not_found');
            return response()->json(['status' => false, 'flag' => 'fail', 'message' => $msg]);
        }

       // Handle allowed_event_ids based on request type
        if ($request->is('api/*')) {
            // Check if allowed_event_ids is already an array
            $allowed_event_ids = $request->allowed_event_ids;
        } else {
            $allowed_event_ids = session('allowed_event_ids', []);
        }
        
        $today = now();

        // Get basic booking information
        $firstBooking = $bookings->first();
        $basicInfo = $this->getBasicBookingInfo($firstBooking, $today);
        
        // Process tickets and attendees data
        $tickets = $this->processTicketsData($bookings, $today);

        // Validate all bookings
        foreach ($bookings as $booking) {
            $validation = $this->validateBookingAccess($booking, $allowed_event_ids);
            if (!$validation['valid']) {
                return response()->json(['status' => false, 'flag' => 'fail', 'message' => $validation['message']]);
            }
        }

        // Create check-in records
        $checkinResult = $this->createCheckinRecords($bookings, $today);
        $wasRecentlyCreated = $checkinResult['wasRecentlyCreated'];
        $firstScanRecord = $checkinResult['records'][0];

        // Prepare response data
        $responseData = [
            'status' => true,
            'event_title' => $basicInfo['event_title'],
            'tickets' => $tickets,
            'order_number' => $basicInfo['order_number'],
            'customer_name' => $basicInfo['customer_name'],
            'customer_email' => $basicInfo['customer_email'],
            'is_bulk' => $basicInfo['is_bulk'],
            'distributor_tag' => $basicInfo['distributor_tag'],
        ];

        if ($wasRecentlyCreated) {
            $responseData['flag'] = 'success';
            $responseData['checkin_date'] = $basicInfo['checkin_date'];
            $responseData['checkin_time'] = $basicInfo['checkin_time'];
        } else {
            $responseData['flag'] = 'warning';
            $responseData['checkin_time'] = Carbon::parse($firstScanRecord->check_in_time)->format('h:i A');
            $responseData['checkin_date'] = Carbon::parse($firstScanRecord->event_start_date)->format('d M Y');
        }

        return response()->json($responseData);
    }

    public function getBookingDetails(Request $request)
    {
        $request->validate([
            'order_number' => 'required',
            'scan_all' => 'sometimes|boolean',
        ],['order_number.required' => __('eventmie-pro::em.ticket_not_found')]);

        $bookings = $this->getBookingsFromRequest($request, true);

        if ($bookings->isEmpty()) {
            $msg = __('eventmie-pro::em.ticket_not_found');
            return response()->json(['status' => false, 'flag' => 'fail', 'message' => $msg]);
        }

        $today = now();
        $firstBooking = $bookings->first();
        
        // Get basic booking information
        $basicInfo = $this->getBasicBookingInfo($firstBooking, $today);
        
        // Check if any of the bookings are already checked in
        $isCheckedIn = $this->checkIfAlreadyCheckedIn($bookings, $today);
        
        // Process tickets and attendees data
        $tickets = $this->processTicketsData($bookings, $today);

        // Collect all checkins data
        $checkins = [];
        foreach ($bookings as $booking) {
            if ($booking->checkins) {
                $checkins = array_merge($checkins, $booking->checkins->toArray());
            }
        }

        return response()->json([
            'status' => true,
            'flag' => 'details',
            'event_title' => $basicInfo['event_title'],
            'tickets' => $tickets,
            'order_number' => $basicInfo['order_number'],
            'customer_name' => $basicInfo['customer_name'],
            'customer_email' => $basicInfo['customer_email'],
            'checkin_date' => $basicInfo['checkin_date'],
            'checkin_time' => $basicInfo['checkin_time'],
            'is_checked_in' => $isCheckedIn,
            'checkins' => $checkins,
            'is_bulk' => $basicInfo['is_bulk'],
            'distributor_tag' => $basicInfo['distributor_tag'],
        ]);
    }

    /**
     * Fetch bookings based on order_number from request
     */
    private function getBookingsFromRequest(Request $request, $get_checkins = false)
    {
        $scanAll = $request->input('scan_all', 0);
        // Strip any single or double quotes from the order number
        $orderNumber = trim($request->order_number, "'\"");

        $select = [
            'bookings.id', 
            'bookings.event_id', 
            'bookings.order_number', 
            'bookings.customer_name', 
            'bookings.customer_email', 
            'bookings.ticket_id', 
            'bookings.ticket_title', 
            'bookings.status', 
            'bookings.is_paid', 
            'bookings.event_title', 
            'bookings.event_start_date', 
            'bookings.event_end_date', 
            'bookings.common_order', 
            'bookings.is_bulk', 
            'bookings.distributor_tag', 
        ];        
        if ($scanAll) {
            $query = Booking::select($select)
                ->with(['attendees']);
            
            if ($get_checkins) {
                $query->with(['checkins']);
            }
            
            return $query->where(['order_number' => $orderNumber, 'status' => 1])
                ->get();
        } else {
            $query = Booking::select($select)
                ->with(['attendees']);
            
            if ($get_checkins) {
                $query->with(['checkins']);
            }
            
            return $query->whereIn('common_order', function($subquery) use ($orderNumber) {
                    $subquery->select('common_order')
                        ->from('bookings')
                        ->where('order_number', $orderNumber)
                        ->where('status', 1);
                })
                ->get();
        }
    }

    /**
     * Process tickets and attendees data
     */
    private function processTicketsData($bookings, $today)
    {
        $tickets = [];
        foreach ($bookings->groupBy('ticket_id') as $ticket_id => $ticketBookings) {
            $ticketTitle = $ticketBookings->first()->ticket_title ?? '';
            $attendees = collect();
            foreach ($ticketBookings as $booking) {
                $attendees = $attendees->merge($booking->attendees);
            }
            $tickets[] = [
                'ticket_id' => $ticket_id,
                'ticket_title' => $ticketTitle,
                'attendees' => $attendees->map(function($attendee) use ($today) {
                    return [
                        'name' => $attendee->name,
                        'email' => $attendee->email,
                        'seat_name' => $attendee->seat_name,
                        'checkin_time' => $today->format('h:i A'),
                        'checkin_date' => $today->format('d M Y'),
                        'booking_id' => $attendee->booking_id
                    ];
                })->values()->toArray(),
            ];
        }
        return $tickets;
    }

    /**
     * Get basic booking information
     */
    private function getBasicBookingInfo($firstBooking, $today)
    {
        return [
            'event_title' => $firstBooking->event_title ?? '',
            'order_number' => $firstBooking->order_number,
            'customer_name' => $firstBooking->customer_name ?? '',
            'customer_email' => $firstBooking->customer_email ?? '',
            'checkin_date' => $today->format('d M Y'),
            'checkin_time' => $today->format('h:i A'),
            'is_bulk' => $firstBooking->is_bulk ?? 0,
            'distributor_tag' => $firstBooking->distributor_tag ?? ''
        ];
    }

    /**
     * Validate booking access and permissions
     */
    private function validateBookingAccess($booking, $allowed_event_ids)
    {
        // Validate event access
        if (!Auth::user()->hasRole('admin')) {
            $eventFound = false;
            $scanOnEventDayOnly = false;
            
            foreach ($allowed_event_ids as $allowed_event) {
                if ($allowed_event['event_id'] == $booking->event_id) {
                    $eventFound = true;
                    $scanOnEventDayOnly = $allowed_event['scan_on_event_day_only'];
                    break;
                }
            }
            
            if (!$eventFound) {
                return ['valid' => false, 'message' => __('eventmie-pro::em.not_authorized_scan_event')];
            }
        }

        // Validate booking status and payment
        if ($booking->status != 1) {
            return ['valid' => false, 'message' => __('eventmie-pro::em.ticket_not_valid_cancelled')];
        }
        if ($booking->is_paid != 1) {
            return ['valid' => false, 'message' => __('eventmie-pro::em.ticket_not_paid')];
        }
        
        // UNIVERSAL EXPIRY CHECK - applies to ALL users including admins
        $today = now();
        if ($today->toDateString() > $booking->event_end_date) {
            return ['valid' => false, 'message' => __('eventmie-pro::em.expired')];
        }
        
        // Validate event date based on scan_on_event_day_only setting (only for non-admin users)
        if (!Auth::user()->hasRole('admin')) {
            if ($scanOnEventDayOnly) {
                // If enabled, only allow scanning on event day
                if ($today->toDateString() < $booking->event_start_date) {
                    return ['valid' => false, 'message' => __('eventmie-pro::em.ticket_scan_event_day_only')];
                }
            }
        }

        return ['valid' => true];
    }

    /**
     * Check if bookings are already checked in
     */
    private function checkIfAlreadyCheckedIn($bookings, $today)
    {
        foreach ($bookings as $booking) {
            $checkin = Checkin::where([
                'event_id' => $booking->event_id,
                'booking_id' => $booking->id,
                'event_start_date' => $today->toDateString()
            ])->first();
            
            if ($checkin) {
                return true;
            }
        }
        return false;
    }

    /**
     * Create check-in records for all bookings
     */
    private function createCheckinRecords($bookings, $today)
    {
        $scanRecords = [];
        $wasRecentlyCreated = false;
        
        foreach ($bookings as $booking) {
            $scanRecord = Checkin::firstOrCreate(
                [
                    'event_id' => $booking->event_id,
                    'booking_id' => $booking->id,
                    'event_start_date' => $today->toDateString()
                ],
                [
                    'user_id' => Auth::id(),
                    'check_in_time' => $today->format('H:i:s')
                ]
            );
            
            $scanRecords[] = $scanRecord;
            if ($scanRecord->wasRecentlyCreated) {
                $wasRecentlyCreated = true;
            }
        }
        
        return ['records' => $scanRecords, 'wasRecentlyCreated' => $wasRecentlyCreated];
    }



}
