<?php

namespace App\Services;

use App\Models\Slot;
use Carbon\Carbon;

class CalendarService
{
    /**
     * Build calendar grid for Mon–Fri with your six daily times.
     *
     * @param  Carbon  $start            Monday of the week you want to display
     * @param  Carbon  $now              Current time (use 'Europe/London')
     * @param  bool    $applyShortNotice If true, mark ≤ 120 min as closed (student view)
     * @return array{headers: array<int, array{date:string,label:string}>, rows: array<int, array{time:string,label:string,cells:array<int,array{date:string,time:string,slot:int|null,status:string,class:string,name:?string}>}>, times: string[]}
     */
    public function build(Carbon $start, Carbon $now, bool $applyShortNotice): array
    {
        $end = $start->copy()->addDays(6);

        $weekdays = [1,2,3,4,5]; // Mon..Fri
        $times = ['09:00:00','10:00:00','11:00:00','14:00:00','15:00:00','16:00:00'];

        // Get all slots with bookings in the visible week
        $slots = Slot::with(['bookings' => function ($q) use ($start, $end) {
            $q->whereBetween('date', [$start->toDateString(), $end->toDateString()]);
        }])->get();

        // Map slots by weekday/time for O(1) lookup in the loop
        $map = [];
        foreach ($slots as $s) {
            $map[(int)$s->weekday][$s->time] = $s;
        }

        // Column headers
        $headers = [];
        for ($i = 0; $i < 5; $i++) {
            $d = $start->copy()->addDays($i);
            $headers[] = [
                'date'  => $d->toDateString(),
                'label' => $d->format('D d M'),
            ];
        }

        // Rows (each time)
        $rows = [];
        foreach ($times as $time) {
            $cells = [];
            foreach ($weekdays as $wd) {
                $date = $start->copy()->addDays($wd - 1)->toDateString();
                $slot = $map[$wd][$time] ?? null;
                $booking = $slot ? $slot->bookings->firstWhere('date', $date) : null;

                // Compute short-notice closure only when required (students)
                $sessionStart = Carbon::createFromFormat('Y-m-d H:i:s', "{$date} {$time}", $now->timezone);
                $minutesUntil = $now->diffInMinutes($sessionStart, false);
                $tooSoon = $applyShortNotice ? ($minutesUntil <= 120) : false;

                // Decide status + cell class
                $status = 'closed';
                $class  = 'bg-gray-100';
                $name   = null;

                if ($booking) {
                    if ($booking->status === 'booked')     { $status = 'booked'; $class = 'bg-red-200'; }
                    elseif ($booking->status === 'blocked') { $status = 'blocked'; $class = 'bg-yellow-200'; }
                } elseif (!$slot) {
                    $status = 'not_seeded'; // slot wasn’t seeded for this weekday/time
                } elseif ($minutesUntil < 0 || $tooSoon) {
                    $status = 'closed';
                } else {
                    $status = 'free';
                    $class  = 'bg-green-100';
                }

                if ($booking && $booking->student_name) {
                    $name = $booking->student_name;
                }

                $cells[] = [
                    'date'   => $date,
                    'time'   => $time,
                    'slot'   => $slot?->id,
                    'status' => $status, // free | booked | blocked | closed | not_seeded
                    'class'  => $class,
                    'name'   => $name,
                ];
            }

            $rows[] = [
                'time'  => $time,
                'label' => substr($time, 0, 5),
                'cells' => $cells,
            ];
        }

        return [
            'headers' => $headers,
            'rows'    => $rows,
            'times'   => $times,
        ];
    }
}