<?php

namespace App\Services;

use App\Models\Equipment;
use App\Models\TimeSlot;
use App\Models\EquipmentReservation;
use Carbon\Carbon;

class TimeSlotService
{
    /**
     * Generate time slots for equipment for a date range.
     */
    public function generateTimeSlots(Equipment $equipment, Carbon $startDate, Carbon $endDate): int
    {
        $slotsGenerated = 0;
        $currentDate = $startDate->copy();

        while ($currentDate <= $endDate) {
            $slotsGenerated += $this->generateTimeSlotsForDate($equipment, $currentDate);
            $currentDate->addDay();
        }

        return $slotsGenerated;
    }

    /**
     * Generate time slots for a specific date.
     */
    public function generateTimeSlotsForDate(Equipment $equipment, Carbon $date): int
    {
        $startTime = Carbon::parse($equipment->start_time);
        $endTime = Carbon::parse($equipment->end_time);
        $slotDuration = $equipment->slot_duration;
        
        $currentTime = $startTime->copy();
        $slotsGenerated = 0;
        
        while ($currentTime < $endTime) {
            $slotEndTime = $currentTime->copy()->addMinutes($slotDuration);
            
            // Check if this slot is already reserved
            $existingReservation = $equipment->reservations()
                ->where('reservation_date', $date->toDateString())
                ->where('start_time', $currentTime->format('H:i'))
                ->where('status', 'confirmed')
                ->first();
            
            $status = $existingReservation ? 'reserved' : 'available';
            $reservationId = $existingReservation ? $existingReservation->id : null;
            
            TimeSlot::updateOrCreate(
                [
                    'equipment_id' => $equipment->id,
                    'slot_date' => $date->toDateString(),
                    'start_time' => $currentTime->format('H:i'),
                ],
                [
                    'end_time' => $slotEndTime->format('H:i'),
                    'status' => $status,
                    'reservation_id' => $reservationId,
                ]
            );
            
            $slotsGenerated++;
            $currentTime->addMinutes($slotDuration);
        }
        
        return $slotsGenerated;
    }

    /**
     * Reserve a time slot for a reservation.
     */
    public function reserveTimeSlot(EquipmentReservation $reservation): bool
    {
        $timeSlot = TimeSlot::where('equipment_id', $reservation->equipment_id)
            ->where('slot_date', $reservation->reservation_date)
            ->where('start_time', $reservation->start_time)
            ->first();

        if (!$timeSlot) {
            // Create the time slot if it doesn't exist
            $equipment = $reservation->equipment;
            $startTime = Carbon::parse($reservation->start_time);
            $endTime = $startTime->copy()->addMinutes($equipment->slot_duration);

            $timeSlot = TimeSlot::create([
                'equipment_id' => $reservation->equipment_id,
                'slot_date' => $reservation->reservation_date,
                'start_time' => $reservation->start_time,
                'end_time' => $endTime->format('H:i'),
                'status' => 'reserved',
                'reservation_id' => $reservation->id,
            ]);
        } else {
            // Update existing time slot
            $timeSlot->update([
                'status' => 'reserved',
                'reservation_id' => $reservation->id,
            ]);
        }

        return true;
    }

    /**
     * Release a time slot when a reservation is cancelled.
     */
    public function releaseTimeSlot(EquipmentReservation $reservation): bool
    {
        $timeSlot = TimeSlot::where('equipment_id', $reservation->equipment_id)
            ->where('slot_date', $reservation->reservation_date)
            ->where('start_time', $reservation->start_time)
            ->where('reservation_id', $reservation->id)
            ->first();

        if ($timeSlot) {
            $timeSlot->update([
                'status' => 'available',
                'reservation_id' => null,
            ]);
        }

        return true;
    }

    /**
     * Get time slot statistics for analytics.
     */
    public function getTimeSlotStatistics($startDate = null, $endDate = null): array
    {
        $startDate = $startDate ? Carbon::parse($startDate) : now()->startOfMonth();
        $endDate = $endDate ? Carbon::parse($endDate) : now()->endOfMonth();

        $query = TimeSlot::whereBetween('slot_date', [$startDate, $endDate]);

        $stats = [
            'total_slots' => $query->count(),
            'available_slots' => $query->where('status', 'available')->count(),
            'reserved_slots' => $query->where('status', 'reserved')->count(),
            'blocked_slots' => $query->where('status', 'blocked')->count(),
            'maintenance_slots' => $query->where('status', 'maintenance')->count(),
            'utilization_rate' => 0,
            'by_equipment' => [],
            'by_date' => [],
        ];

        // Calculate utilization rate
        if ($stats['total_slots'] > 0) {
            $stats['utilization_rate'] = round(($stats['reserved_slots'] / $stats['total_slots']) * 100, 2);
        }

        // Get statistics by equipment
        $equipmentStats = TimeSlot::whereBetween('slot_date', [$startDate, $endDate])
            ->with('equipment')
            ->selectRaw('equipment_id, status, COUNT(*) as count')
            ->groupBy('equipment_id', 'status')
            ->get();

        foreach ($equipmentStats as $stat) {
            if (!isset($stats['by_equipment'][$stat->equipment_id])) {
                $stats['by_equipment'][$stat->equipment_id] = [
                    'name' => $stat->equipment->name ?? 'Unknown',
                    'total' => 0,
                    'available' => 0,
                    'reserved' => 0,
                    'blocked' => 0,
                    'maintenance' => 0,
                ];
            }
            $stats['by_equipment'][$stat->equipment_id]['total'] += $stat->count;
            $stats['by_equipment'][$stat->equipment_id][$stat->status] = $stat->count;
        }

        // Get statistics by date
        $dateStats = TimeSlot::whereBetween('slot_date', [$startDate, $endDate])
            ->selectRaw('slot_date, status, COUNT(*) as count')
            ->groupBy('slot_date', 'status')
            ->get();

        foreach ($dateStats as $stat) {
            $dateKey = $stat->slot_date->format('Y-m-d');
            if (!isset($stats['by_date'][$dateKey])) {
                $stats['by_date'][$dateKey] = [
                    'date' => $stat->slot_date->format('M d, Y'),
                    'total' => 0,
                    'available' => 0,
                    'reserved' => 0,
                    'blocked' => 0,
                    'maintenance' => 0,
                ];
            }
            $stats['by_date'][$dateKey]['total'] += $stat->count;
            $stats['by_date'][$dateKey][$stat->status] = $stat->count;
        }

        return $stats;
    }

    /**
     * Block time slots for maintenance or other reasons.
     */
    public function blockTimeSlots(Equipment $equipment, Carbon $startDate, Carbon $endDate, $startTime, $endTime, $notes = null): int
    {
        $slotsBlocked = 0;
        $currentDate = $startDate->copy();

        while ($currentDate <= $endDate) {
            $timeSlots = TimeSlot::where('equipment_id', $equipment->id)
                ->where('slot_date', $currentDate->toDateString())
                ->where('start_time', '>=', $startTime)
                ->where('end_time', '<=', $endTime)
                ->where('status', 'available')
                ->get();

            foreach ($timeSlots as $timeSlot) {
                $timeSlot->update([
                    'status' => 'maintenance',
                    'notes' => $notes,
                ]);
                $slotsBlocked++;
            }

            $currentDate->addDay();
        }

        return $slotsBlocked;
    }
} 