<?php

namespace App\Livewire\Appointments;

use Livewire\Component;
use App\Models\Appointment;
use App\Models\Technician;
use Carbon\Carbon;

class TimeSlots extends Component
{
    public $selectedDate;
    public $selectedTechnician = '';
    public $serviceDuration = 60; // minutes
    public $availableSlots = [];
    public $bookedSlots = [];
    public $selectedSlot = '';
    public $timeSlots = [];
    public $technicians = [];
    
    // Business hours configuration
    public $businessStart = '08:00';
    public $businessEnd = '18:00';
    public $slotInterval = 30; // minutes
    public $lunchStart = '12:00';
    public $lunchEnd = '13:00';
    
    public function mount($date = null, $technicianId = null, $duration = 60)
    {
        $this->selectedDate = $date ?: now()->addDay()->format('Y-m-d');
        $this->selectedTechnician = $technicianId ?: '';
        $this->serviceDuration = $duration;
        $this->technicians = Technician::where('status', 'active')->orderBy('first_name')->get();
        
        $this->generateTimeSlots();
        $this->loadBookedSlots();
        $this->calculateAvailableSlots();
    }

    public function updatedSelectedDate()
    {
        $this->selectedSlot = '';
        $this->generateTimeSlots();
        $this->loadBookedSlots();
        $this->calculateAvailableSlots();
        $this->dispatch('date-changed', date: $this->selectedDate);
    }

    public function updatedSelectedTechnician()
    {
        $this->selectedSlot = '';
        $this->loadBookedSlots();
        $this->calculateAvailableSlots();
        $this->dispatch('technician-changed', technicianId: $this->selectedTechnician);
    }

    public function updatedServiceDuration()
    {
        $this->selectedSlot = '';
        $this->calculateAvailableSlots();
    }

    public function selectSlot($time)
    {
        $this->selectedSlot = $time;
        $this->dispatch('slot-selected', [
            'date' => $this->selectedDate,
            'time' => $time,
            'technician_id' => $this->selectedTechnician,
            'duration' => $this->serviceDuration
        ]);
    }

    public function clearSelection()
    {
        $this->selectedSlot = '';
        $this->dispatch('slot-cleared');
    }

    private function generateTimeSlots()
    {
        $this->timeSlots = [];
        $date = Carbon::parse($this->selectedDate);
        
        // Don't show slots for past dates
        if ($date->isPast() && !$date->isToday()) {
            return;
        }
        
        $start = $date->copy()->setTimeFromTimeString($this->businessStart);
        $end = $date->copy()->setTimeFromTimeString($this->businessEnd);
        $lunchStart = $date->copy()->setTimeFromTimeString($this->lunchStart);
        $lunchEnd = $date->copy()->setTimeFromTimeString($this->lunchEnd);
        
        $current = $start->copy();
        
        while ($current < $end) {
            $timeString = $current->format('H:i');
            
            // Skip lunch time
            if ($current >= $lunchStart && $current < $lunchEnd) {
                $current->addMinutes($this->slotInterval);
                continue;
            }
            
            // Skip past times for today
            if ($date->isToday() && $current <= now()) {
                $current->addMinutes($this->slotInterval);
                continue;
            }
            
            $this->timeSlots[] = [
                'time' => $timeString,
                'label' => $current->format('g:i A'),
                'datetime' => $current->copy(),
            ];
            
            $current->addMinutes($this->slotInterval);
        }
    }

    private function loadBookedSlots()
    {
        $query = Appointment::whereDate('scheduled_datetime', $this->selectedDate)
            ->whereNotIn('status', ['cancelled', 'no_show']);
            
        if ($this->selectedTechnician) {
            $query->where('assigned_technician_id', $this->selectedTechnician);
        }
        
        $appointments = $query->get();
        
        $this->bookedSlots = [];
        
        foreach ($appointments as $appointment) {
            $startTime = Carbon::parse($appointment->scheduled_datetime);
            $endTime = $startTime->copy()->addMinutes($appointment->estimated_duration_minutes);
            
            // Mark all slots that overlap with this appointment as booked
            $current = $startTime->copy();
            while ($current < $endTime) {
                $this->bookedSlots[] = [
                    'time' => $current->format('H:i'),
                    'appointment_id' => $appointment->id,
                    'customer_name' => $appointment->customer->first_name . ' ' . $appointment->customer->last_name,
                    'service' => $appointment->service_requested,
                    'status' => $appointment->status,
                ];
                $current->addMinutes($this->slotInterval);
            }
        }
    }

    private function calculateAvailableSlots()
    {
        $this->availableSlots = [];
        $bookedTimes = collect($this->bookedSlots)->pluck('time')->toArray();
        
        foreach ($this->timeSlots as $slot) {
            $isAvailable = true;
            $slotStart = Carbon::parse($this->selectedDate . ' ' . $slot['time']);
            $slotEnd = $slotStart->copy()->addMinutes($this->serviceDuration);
            
            // Check if this slot and required duration would conflict with any booked slot
            $checkTime = $slotStart->copy();
            while ($checkTime < $slotEnd) {
                if (in_array($checkTime->format('H:i'), $bookedTimes)) {
                    $isAvailable = false;
                    break;
                }
                $checkTime->addMinutes($this->slotInterval);
            }
            
            // Check if slot extends beyond business hours
            $businessEnd = Carbon::parse($this->selectedDate . ' ' . $this->businessEnd);
            if ($slotEnd > $businessEnd) {
                $isAvailable = false;
            }
            
            // Check if slot conflicts with lunch time
            $lunchStart = Carbon::parse($this->selectedDate . ' ' . $this->lunchStart);
            $lunchEnd = Carbon::parse($this->selectedDate . ' ' . $this->lunchEnd);
            if ($slotStart < $lunchEnd && $slotEnd > $lunchStart) {
                $isAvailable = false;
            }
            
            if ($isAvailable) {
                $this->availableSlots[] = $slot['time'];
            }
        }
    }

    public function getSlotStatus($time)
    {
        $bookedSlot = collect($this->bookedSlots)->firstWhere('time', $time);
        
        if ($bookedSlot) {
            return [
                'status' => 'booked',
                'data' => $bookedSlot
            ];
        }
        
        if (in_array($time, $this->availableSlots)) {
            return [
                'status' => 'available',
                'data' => null
            ];
        }
        
        return [
            'status' => 'unavailable',
            'data' => null
        ];
    }

    public function getAvailableSlotsForApi()
    {
        return collect($this->timeSlots)
            ->filter(function ($slot) {
                return in_array($slot['time'], $this->availableSlots);
            })
            ->values()
            ->toArray();
    }

    public function getBookedSlotsInfo()
    {
        return collect($this->bookedSlots)
            ->groupBy('time')
            ->map(function ($slots) {
                return $slots->first();
            })
            ->values()
            ->toArray();
    }

    public function isSlotSelected($time)
    {
        return $this->selectedSlot === $time;
    }

    public function getNextAvailableDate()
    {
        $date = Carbon::parse($this->selectedDate);
        $maxDays = 30; // Look ahead 30 days
        
        for ($i = 1; $i <= $maxDays; $i++) {
            $checkDate = $date->copy()->addDays($i);
            
            // Skip weekends (assuming business doesn't operate on weekends)
            if ($checkDate->isWeekend()) {
                continue;
            }
            
            // Generate slots for this date
            $tempDate = $this->selectedDate;
            $this->selectedDate = $checkDate->format('Y-m-d');
            $this->generateTimeSlots();
            $this->loadBookedSlots();
            $this->calculateAvailableSlots();
            
            if (!empty($this->availableSlots)) {
                $nextDate = $this->selectedDate;
                $this->selectedDate = $tempDate; // Restore original date
                $this->generateTimeSlots();
                $this->loadBookedSlots();
                $this->calculateAvailableSlots();
                return $nextDate;
            }
            
            $this->selectedDate = $tempDate; // Restore original date
        }
        
        return null;
    }

    public function render()
    {
        return view('livewire.appointments.time-slots', [
            'nextAvailableDate' => $this->getNextAvailableDate(),
        ]);
    }
}
