<?php
declare(strict_types=1);

namespace App\Modules\PoolManagement\Services;

use App\Core\App;
use App\Modules\PoolManagement\Models\PoolConfiguration;

final class PoolGridService
{
    public static function getGridState(int $poolConfigId, string $date, ?string $currentTime = null): array
    {
        $config = PoolConfiguration::find($poolConfigId);
        if (!$config) {
            return ['error' => 'Pool not found'];
        }

        $lanes = $config->getLanes();
        $hours = $config->getOperatingHours();
        $slotMinutes = (int) ($hours['slot_minutes'] ?? 60);
        $startHour = $hours['start'] ?? '06:00';
        $endHour = $hours['end'] ?? '22:00';

        $timeSlots = self::generateTimeSlots($startHour, $endHour, $slotMinutes);

        $db = App::getInstance()->db();
        $bookings = $db->select(
            "SELECT * FROM pool_bookings
             WHERE pool_config_id = ? AND booking_date = ? AND status NOT IN ('cancelled')
             ORDER BY start_time ASC",
            [$poolConfigId, $date]
        );

        $cells = [];
        foreach ($lanes as $lane) {
            $laneNum = (int) $lane['lane_number'];
            $cells[$laneNum] = [];

            foreach ($timeSlots as $slot) {
                $slotStart = $slot['start'];
                $slotEnd = $slot['end'];
                $cellStatus = 'available';
                $cellBooking = null;

                foreach ($bookings as $booking) {
                    $bookedLanes = json_decode($booking['lanes_json'] ?? '[]', true);
                    if (!is_array($bookedLanes) || !in_array($laneNum, $bookedLanes)) {
                        continue;
                    }

                    if ($booking['start_time'] < $slotEnd && $booking['end_time'] > $slotStart) {
                        if ($booking['booking_type'] === 'maintenance') {
                            $cellStatus = 'maintenance';
                        } elseif ($booking['status'] === 'checked_in') {
                            $cellStatus = 'in_progress';
                        } else {
                            $cellStatus = 'booked';
                        }
                        $cellBooking = [
                            'id'         => (int) $booking['id'],
                            'type'       => $booking['booking_type'],
                            'booker'     => $booking['booker_name'] ?? '',
                            'swimmers'   => (int) $booking['expected_swimmers'],
                            'start'      => $booking['start_time'],
                            'end'        => $booking['end_time'],
                            'status'     => $booking['status'],
                        ];
                        break;
                    }
                }

                $cells[$laneNum][$slotStart] = [
                    'status'  => $cellStatus,
                    'booking' => $cellBooking,
                ];
            }
        }

        return [
            'pool'       => [
                'id'     => (int) $config->id,
                'name'   => $config->name_ar,
                'length' => (float) $config->length_meters,
                'width'  => (float) $config->width_meters,
            ],
            'lanes'      => $lanes,
            'time_slots' => $timeSlots,
            'cells'      => $cells,
            'date'       => $date,
        ];
    }

    public static function checkLaneAvailability(int $poolConfigId, string $date, string $startTime, string $endTime, array $laneNumbers): array
    {
        $db = App::getInstance()->db();

        $bookings = $db->select(
            "SELECT id, lanes_json, booking_type, booker_name, start_time, end_time
             FROM pool_bookings
             WHERE pool_config_id = ? AND booking_date = ? AND status NOT IN ('cancelled')
             AND start_time < ? AND end_time > ?",
            [$poolConfigId, $date, $endTime, $startTime]
        );

        $conflicts = [];
        foreach ($bookings as $booking) {
            $bookedLanes = json_decode($booking['lanes_json'] ?? '[]', true);
            $overlap = array_intersect($laneNumbers, is_array($bookedLanes) ? $bookedLanes : []);
            if (!empty($overlap)) {
                $conflicts[] = [
                    'booking_id' => (int) $booking['id'],
                    'lanes'      => array_values($overlap),
                    'type'       => $booking['booking_type'],
                    'booker'     => $booking['booker_name'] ?? '',
                    'time'       => $booking['start_time'] . ' - ' . $booking['end_time'],
                ];
            }
        }

        return [
            'available' => empty($conflicts),
            'conflicts' => $conflicts,
        ];
    }

    private static function generateTimeSlots(string $start, string $end, int $slotMinutes): array
    {
        $slots = [];
        $current = strtotime($start);
        $endTs = strtotime($end);

        while ($current < $endTs) {
            $slotStart = date('H:i', $current);
            $next = $current + ($slotMinutes * 60);
            $slotEnd = date('H:i', $next);
            $slots[] = ['start' => $slotStart, 'end' => $slotEnd];
            $current = $next;
        }

        return $slots;
    }
}
