<?php

namespace App\Livewire\Schedule;

use App\Domain\Shared\Traits\UsesBranchScope;
use App\Domain\Training\Models\TrainingGroup;
use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Models\TrainingSession;
use App\Models\User;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('الجدول الأسبوعي')]
class WeeklySchedule extends Component
{
    use UsesBranchScope;

    #[Url]
    public string $programFilter = '';

    #[Url]
    public string $trainerFilter = '';

    public string $weekStart = '';

    public function mount(): void
    {
        $this->authorize('schedules.view');

        // Start week on Saturday (Arabic week starts Saturday)
        $today = Carbon::today();
        $this->weekStart = $today->startOfWeek(Carbon::SATURDAY)->format('Y-m-d');
    }

    public function previousWeek(): void
    {
        $this->weekStart = Carbon::parse($this->weekStart)->subWeek()->format('Y-m-d');
    }

    public function nextWeek(): void
    {
        $this->weekStart = Carbon::parse($this->weekStart)->addWeek()->format('Y-m-d');
    }

    public function updatedProgramFilter(): void
    {
        $this->trainerFilter = '';
    }

    public function goToToday(): void
    {
        $today = Carbon::today();
        $this->weekStart = $today->startOfWeek(Carbon::SATURDAY)->format('Y-m-d');
    }

    #[Computed]
    public function weekDays(): array
    {
        $start = Carbon::parse($this->weekStart);
        $days = [];

        $arabicDayNames = [
            Carbon::SATURDAY => 'السبت',
            Carbon::SUNDAY => 'الأحد',
            Carbon::MONDAY => 'الاثنين',
            Carbon::TUESDAY => 'الثلاثاء',
            Carbon::WEDNESDAY => 'الأربعاء',
            Carbon::THURSDAY => 'الخميس',
        ];

        for ($i = 0; $i < 6; $i++) {
            $date = $start->copy()->addDays($i);
            $days[] = [
                'date' => $date->format('Y-m-d'),
                'name' => $arabicDayNames[$date->dayOfWeek] ?? $date->translatedDayName,
                'formatted' => $date->format('m/d'),
                'isToday' => $date->isToday(),
            ];
        }

        return $days;
    }

    #[Computed]
    public function timeSlots(): array
    {
        $slots = [];
        for ($hour = 8; $hour <= 22; $hour++) {
            $slots[] = sprintf('%02d:00', $hour);
        }

        return $slots;
    }

    public function render()
    {
        $weekEnd = Carbon::parse($this->weekStart)->addDays(5)->format('Y-m-d');

        // TrainingSession carries its own branch_id and the BranchScope, so the
        // grid narrows itself. The old whereHas('group', branch_id) attributed
        // a session through its group instead of through the session's own
        // column, and silently dropped any session whose group is gone.
        $sessions = TrainingSession::query()
            ->with(['group.program', 'facility', 'trainer'])
            ->where('session_date', '>=', $this->weekStart)
            ->where('session_date', '<=', $weekEnd)
            ->whereNotIn('status', ['cancelled', 'rescheduled'])
            ->when($this->programFilter, fn ($q) => $q->whereHas('group', fn ($gq) => $gq->where('training_program_id', $this->programFilter)))
            ->when($this->trainerFilter, fn ($q) => $q->where('trainer_id', $this->trainerFilter))
            ->orderBy('start_time')
            ->get();

        // Group sessions by date for the grid
        $sessionsByDate = $sessions->groupBy(fn ($s) => $s->session_date->format('Y-m-d'));

        // Programs for filter. TrainingProgram is a SHARED model: branch_id
        // NULL means every branch uses that programme, so the hand-written
        // where('branch_id', ...) that used to be here hid the academy-wide
        // programmes from every branch. The global scope reads the null right.
        $programs = TrainingProgram::query()
            ->select('id', 'name_ar')
            ->orderBy('name_ar')
            ->get();

        // Trainers for filter — cascade from program.
        //
        // A user has no branch of its own, so listing every trainer-role
        // account put staff from the other branches in the dropdown beside a
        // grid that was already filtered. The list now comes from this
        // branch's own groups and sessions: both models carry BranchScope, so
        // these two plucks narrow themselves without naming branch_id at all.
        $trainerIds = TrainingGroup::query()
            ->whereNotNull('head_trainer_id')
            ->when($this->programFilter, fn ($q) => $q->where('training_program_id', $this->programFilter))
            ->distinct()
            ->pluck('head_trainer_id')
            ->merge(
                TrainingSession::query()
                    ->whereNotNull('trainer_id')
                    ->when($this->programFilter, fn ($q) => $q->whereHas('group', fn ($gq) => $gq->where('training_program_id', $this->programFilter)))
                    ->distinct()
                    ->pluck('trainer_id')
            )
            ->unique()
            ->values();

        $trainers = User::query()
            ->select('id', 'name_ar', 'name')
            ->whereHas('roles', fn ($q) => $q->whereIn('slug', ['trainer', 'head_trainer']))
            ->whereIn('id', $trainerIds)
            ->orderBy('name_ar')
            ->get();

        // Assign colors per program for visual distinction
        $programColors = $this->getProgramColors($sessions);

        return view('livewire.schedule.weekly-schedule', [
            'sessionsByDate' => $sessionsByDate,
            'programs' => $programs,
            'trainers' => $trainers,
            'programColors' => $programColors,
        ]);
    }

    private function getProgramColors($sessions): array
    {
        $colors = [
            'bg-blue-100 border-blue-400 text-blue-800',
            'bg-emerald-100 border-emerald-400 text-emerald-800',
            'bg-amber-100 border-amber-400 text-amber-800',
            'bg-purple-100 border-purple-400 text-purple-800',
            'bg-rose-100 border-rose-400 text-rose-800',
            'bg-cyan-100 border-cyan-400 text-cyan-800',
            'bg-orange-100 border-orange-400 text-orange-800',
            'bg-indigo-100 border-indigo-400 text-indigo-800',
            'bg-teal-100 border-teal-400 text-teal-800',
            'bg-pink-100 border-pink-400 text-pink-800',
        ];

        $programIds = $sessions->pluck('group.training_program_id')->unique()->values();
        $map = [];

        foreach ($programIds as $index => $programId) {
            $map[$programId] = $colors[$index % count($colors)];
        }

        return $map;
    }
}
