<?php

namespace App\Livewire\Appointments;

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

class Calendar extends Component
{
    public $currentDate;
    public $currentMonth;
    public $currentYear;
    public $selectedDate;
    public $selectedTechnician = '';
    public $viewType = 'month'; // month, week, day
    public $calendarDays = [];
    public $appointments = [];
    public $technicians = [];
    public $showAppointmentModal = false;
    public $selectedAppointment = null;

    public function mount()
    {
        $this->currentDate = now();
        $this->currentMonth = $this->currentDate->month;
        $this->currentYear = $this->currentDate->year;
        $this->selectedDate = $this->currentDate->format('Y-m-d');
        $this->technicians = Technician::where('status', 'active')->orderBy('first_name')->get();
        $this->generateCalendar();
        $this->loadAppointments();
    }

    public function updatedSelectedTechnician()
    {
        $this->loadAppointments();
    }

    public function setViewType($type)
    {
        $this->viewType = $type;
        $this->generateCalendar();
        $this->loadAppointments();
    }

    public function previousPeriod()
    {
        switch ($this->viewType) {
            case 'month':
                $this->currentDate = $this->currentDate->subMonth();
                break;
            case 'week':
                $this->currentDate = $this->currentDate->subWeek();
                break;
            case 'day':
                $this->currentDate = $this->currentDate->subDay();
                break;
        }
        
        $this->currentMonth = $this->currentDate->month;
        $this->currentYear = $this->currentDate->year;
        $this->generateCalendar();
        $this->loadAppointments();
    }

    public function nextPeriod()
    {
        switch ($this->viewType) {
            case 'month':
                $this->currentDate = $this->currentDate->addMonth();
                break;
            case 'week':
                $this->currentDate = $this->currentDate->addWeek();
                break;
            case 'day':
                $this->currentDate = $this->currentDate->addDay();
                break;
        }
        
        $this->currentMonth = $this->currentDate->month;
        $this->currentYear = $this->currentDate->year;
        $this->generateCalendar();
        $this->loadAppointments();
    }

    public function today()
    {
        $this->currentDate = now();
        $this->currentMonth = $this->currentDate->month;
        $this->currentYear = $this->currentDate->year;
        $this->selectedDate = $this->currentDate->format('Y-m-d');
        $this->generateCalendar();
        $this->loadAppointments();
    }

    public function selectDate($date)
    {
        $this->selectedDate = $date;
        $this->currentDate = Carbon::parse($date);
        $this->dispatch('date-selected', date: $date);
    }

    public function showAppointmentDetails($appointmentId)
    {
        $this->selectedAppointment = Appointment::with(['customer', 'vehicle', 'assignedTechnician'])
            ->find($appointmentId);
        $this->showAppointmentModal = true;
    }

    public function closeAppointmentModal()
    {
        $this->showAppointmentModal = false;
        $this->selectedAppointment = null;
    }

    private function generateCalendar()
    {
        $this->calendarDays = [];
        
        switch ($this->viewType) {
            case 'month':
                $this->generateMonthCalendar();
                break;
            case 'week':
                $this->generateWeekCalendar();
                break;
            case 'day':
                $this->generateDayCalendar();
                break;
        }
    }

    private function generateMonthCalendar()
    {
        $startOfMonth = $this->currentDate->copy()->startOfMonth();
        $endOfMonth = $this->currentDate->copy()->endOfMonth();
        $startOfCalendar = $startOfMonth->copy()->startOfWeek();
        $endOfCalendar = $endOfMonth->copy()->endOfWeek();

        $current = $startOfCalendar->copy();
        $this->calendarDays = [];

        while ($current <= $endOfCalendar) {
            $this->calendarDays[] = [
                'date' => $current->format('Y-m-d'),
                'day' => $current->day,
                'isCurrentMonth' => $current->month === $this->currentMonth,
                'isToday' => $current->isToday(),
                'isSelected' => $current->format('Y-m-d') === $this->selectedDate,
                'dayName' => $current->format('D'),
            ];
            $current->addDay();
        }
    }

    private function generateWeekCalendar()
    {
        $startOfWeek = $this->currentDate->copy()->startOfWeek();
        $this->calendarDays = [];

        for ($i = 0; $i < 7; $i++) {
            $date = $startOfWeek->copy()->addDays($i);
            $this->calendarDays[] = [
                'date' => $date->format('Y-m-d'),
                'day' => $date->day,
                'isCurrentMonth' => true,
                'isToday' => $date->isToday(),
                'isSelected' => $date->format('Y-m-d') === $this->selectedDate,
                'dayName' => $date->format('l'),
                'fullDate' => $date->format('M j'),
            ];
        }
    }

    private function generateDayCalendar()
    {
        $this->calendarDays = [[
            'date' => $this->currentDate->format('Y-m-d'),
            'day' => $this->currentDate->day,
            'isCurrentMonth' => true,
            'isToday' => $this->currentDate->isToday(),
            'isSelected' => true,
            'dayName' => $this->currentDate->format('l'),
            'fullDate' => $this->currentDate->format('F j, Y'),
        ]];
    }

    private function loadAppointments()
    {
        $query = Appointment::with(['customer', 'vehicle', 'assignedTechnician']);

        switch ($this->viewType) {
            case 'month':
                $startDate = $this->currentDate->copy()->startOfMonth();
                $endDate = $this->currentDate->copy()->endOfMonth();
                break;
            case 'week':
                $startDate = $this->currentDate->copy()->startOfWeek();
                $endDate = $this->currentDate->copy()->endOfWeek();
                break;
            case 'day':
                $startDate = $this->currentDate->copy()->startOfDay();
                $endDate = $this->currentDate->copy()->endOfDay();
                break;
        }

        $query->whereBetween('scheduled_datetime', [$startDate, $endDate]);

        if ($this->selectedTechnician) {
            $query->where('assigned_technician_id', $this->selectedTechnician);
        }

        $appointments = $query->orderBy('scheduled_datetime')->get();

        // Group appointments by date and convert to array for blade template
        $this->appointments = $appointments->groupBy(function ($appointment) {
            return $appointment->scheduled_datetime->format('Y-m-d');
        })->map(function ($dayAppointments) {
            return $dayAppointments->map(function ($appointment) {
                return [
                    'id' => $appointment->id,
                    'scheduled_datetime' => $appointment->scheduled_datetime->toISOString(),
                    'service_requested' => $appointment->service_requested,
                    'status' => $appointment->status,
                    'status_color' => $appointment->status_color,
                    'customer' => [
                        'first_name' => $appointment->customer->first_name ?? '',
                        'last_name' => $appointment->customer->last_name ?? '',
                    ],
                    'assigned_technician' => [
                        'first_name' => $appointment->assignedTechnician->first_name ?? '',
                        'last_name' => $appointment->assignedTechnician->last_name ?? '',
                    ],
                ];
            })->toArray();
        })->toArray();
    }

    public function getTimeSlots()
    {
        $slots = [];
        $start = 8; // 8 AM
        $end = 18; // 6 PM

        for ($hour = $start; $hour < $end; $hour++) {
            $slots[] = [
                'time' => sprintf('%02d:00', $hour),
                'label' => Carbon::createFromTime($hour, 0)->format('g:i A'),
            ];
            $slots[] = [
                'time' => sprintf('%02d:30', $hour),
                'label' => Carbon::createFromTime($hour, 30)->format('g:i A'),
            ];
        }

        return $slots;
    }

    public function getCurrentPeriodLabel()
    {
        switch ($this->viewType) {
            case 'month':
                return $this->currentDate->format('F Y');
            case 'week':
                $start = $this->currentDate->copy()->startOfWeek();
                $end = $this->currentDate->copy()->endOfWeek();
                return $start->format('M j') . ' - ' . $end->format('M j, Y');
            case 'day':
                return $this->currentDate->format('l, F j, Y');
        }
    }

    public function render()
    {
        return view('livewire.appointments.calendar', [
            'currentPeriodLabel' => $this->getCurrentPeriodLabel(),
            'timeSlots' => $this->getTimeSlots(),
            'appointmentCount' => collect($this->appointments)->flatten(1)->count(),
        ]);
    }
}
