<?php

namespace Tests\Feature;

use App\Models\Branch;
use App\Models\ClassSubject;
use App\Models\Period;
use App\Models\SchoolClass;
use App\Models\Staff;
use App\Models\Subject;
use App\Models\TimetableSlot;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

/**
 * The auto-generated timetable's core invariant: a teacher is never double-booked
 * at the same day + period across classes, even when the same teacher is shared
 * between classes.
 */
class TimetableTest extends TestCase
{
    use RefreshDatabase;

    public function test_generated_timetable_never_double_books_a_teacher(): void
    {
        $branch = Branch::create(['name' => 'Main', 'code' => 'MC', 'is_active' => true]);
        User::create(['name' => 'Admin', 'email' => 'a@t.local', 'password' => bcrypt('x'), 'role' => 'super-admin', 'is_active' => true]);
        $this->actingAs(User::first());

        // 4 teaching periods + a break (which must be skipped).
        foreach ([['P1', 0], ['P2', 1], ['P3', 2], ['Break', 3], ['P4', 4]] as [$name, $o]) {
            Period::create(['name' => $name, 'start_time' => '08:00', 'end_time' => '08:45', 'sort_order' => $o]);
        }

        $math = Subject::create(['name' => 'Mathematics', 'max_marks' => 100, 'sort_order' => 0]);
        $sci = Subject::create(['name' => 'Science', 'max_marks' => 100, 'sort_order' => 1]);

        // One shared maths teacher + two science teachers → contention on maths.
        $mathT = Staff::create(['branch_id' => $branch->id, 'type' => 'teacher', 'name' => 'Math Teacher', 'status' => 'active', 'subjects' => 'Mathematics', 'max_periods_per_week' => 40]);
        $sciT = Staff::create(['branch_id' => $branch->id, 'type' => 'teacher', 'name' => 'Science Teacher', 'status' => 'active', 'subjects' => 'Science', 'max_periods_per_week' => 40]);

        // Three classes all needing the same maths teacher.
        foreach (['A', 'B', 'C'] as $section) {
            $class = SchoolClass::create(['name' => "Grade 6 - $section", 'branch_id' => $branch->id, 'level' => 6, 'section' => $section]);
            ClassSubject::create(['class_id' => $class->id, 'subject_id' => $math->id, 'teacher_id' => $mathT->id, 'periods_per_week' => 5]);
            ClassSubject::create(['class_id' => $class->id, 'subject_id' => $sci->id, 'teacher_id' => $sciT->id, 'periods_per_week' => 4]);
        }

        $this->postJson('/api/timetable/generate', [])->assertOk();

        // Invariant: no (day, period, teacher) tuple appears more than once.
        $clashes = TimetableSlot::whereNotNull('teacher_id')
            ->selectRaw('day, period_id, teacher_id, COUNT(*) as n')
            ->groupBy('day', 'period_id', 'teacher_id')
            ->havingRaw('COUNT(*) > 1')->get();

        $this->assertCount(0, $clashes, 'A teacher was double-booked at the same day/period.');
        $this->assertGreaterThan(0, TimetableSlot::count(), 'The generator produced no slots.');
    }
}
