<?php

namespace Tests\Feature\Api;

use App\Models\ClassSection;
use App\Models\Configuration;
use App\Models\Student;
use App\Models\StudentClass;
use App\Models\TeacherClass;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AssignmentApiControllerTest extends TestCase
{
    use RefreshDatabase;

    protected User $user;
    protected User $teacherMain;
    protected User $teacherAssistant;
    protected ClassSection $sectionA;
    protected ClassSection $sectionB;
    protected Student $studentOne;
    protected Student $studentTwo;

    protected function setUp(): void
    {
        parent::setUp();

        $this->seedConfigurations();

        $this->user = User::factory()->create();
        $this->teacherMain = User::factory()->create([
            'firstname' => 'Main',
            'lastname' => 'Teacher',
        ]);
        $this->teacherAssistant = User::factory()->create([
            'firstname' => 'Assistant',
            'lastname' => 'Teacher',
        ]);

        $this->sectionA = ClassSection::factory()->create([
            'section_name' => 'Grade 1 - A',
        ]);

        $this->sectionB = ClassSection::factory()->create([
            'section_name' => 'Grade 2 - B',
        ]);

        $this->studentOne = Student::factory()->create([
            'firstname' => 'Ali',
            'lastname' => 'Hassan',
            'age' => 8,
            'gender' => 'Male',
            'registration_grade' => 'Grade 1',
            'photo_consent' => 1,
            'tuition_paid' => 0,
            'school_id' => 'SCH-001',
            'is_active' => 1,
        ]);

        $this->studentTwo = Student::factory()->create([
            'firstname' => 'Sara',
            'lastname' => 'Ibrahim',
            'age' => 9,
            'gender' => 'Female',
            'registration_grade' => 'Grade 2',
            'photo_consent' => 0,
            'tuition_paid' => 1,
            'school_id' => 'SCH-002',
            'is_active' => 1,
        ]);
    }

    protected function seedConfigurations(): void
    {
        Configuration::query()->create([
            'config_key' => 'semester',
            'config_value' => 'Fall',
        ]);

        Configuration::query()->create([
            'config_key' => 'school_year',
            'config_value' => '2025-2026',
        ]);
    }

    public function test_index_returns_assignment_overview(): void
    {
        TeacherClass::query()->create([
            'teacher_id' => $this->teacherMain->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Morning group',
        ]);

        TeacherClass::query()->create([
            'teacher_id' => $this->teacherAssistant->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'position' => 'ta',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Morning group',
        ]);

        StudentClass::query()->create([
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Morning group',
            'updated_by' => $this->user->id,
        ]);

        $response = $this->actingAs($this->user, 'sanctum')
            ->getJson('/api/assignments?school_year=2025-2026&semester=Fall');

        $response->assertOk()
            ->assertJsonPath('message', 'Assignments retrieved successfully.')
            ->assertJsonPath('data.schoolYear', '2025-2026')
            ->assertJsonPath('data.selectedYear', '2025-2026')
            ->assertJsonPath('data.selectedSemester', 'Fall')
            ->assertJsonPath('data.semester', 'Fall')
            ->assertJsonPath('data.current_school_year', '2025-2026')
            ->assertJsonCount(1, 'data.classSections')
            ->assertJsonPath('data.classSections.0.class_section_id', $this->sectionA->class_section_id)
            ->assertJsonPath('data.classSections.0.class_section_name', 'Grade 1 - A')
            ->assertJsonPath('data.classSections.0.main_teachers.0', 'Main Teacher')
            ->assertJsonPath('data.classSections.0.teacher_assistants.0', 'Assistant Teacher')
            ->assertJsonPath('data.classSections.0.students.0.firstname', 'Ali')
            ->assertJsonPath('data.classSections.0.students.0.lastname', 'Hassan')
            ->assertJsonPath('data.classSections.0.students.0.photo_consent', true)
            ->assertJsonPath('data.classSections.0.students.0.tuition_paid', false)
            ->assertJsonPath('data.classSections.0.description', 'Morning group');
    }

    public function test_index_filters_by_school_year(): void
    {
        TeacherClass::query()->create([
            'teacher_id' => $this->teacherMain->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Included',
        ]);

        TeacherClass::query()->create([
            'teacher_id' => $this->teacherAssistant->id,
            'class_section_id' => $this->sectionB->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2024-2025',
            'description' => 'Excluded',
        ]);

        StudentClass::query()->create([
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Included',
            'updated_by' => $this->user->id,
        ]);

        StudentClass::query()->create([
            'student_id' => $this->studentTwo->id,
            'class_section_id' => $this->sectionB->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2024-2025',
            'description' => 'Excluded',
            'updated_by' => $this->user->id,
        ]);

        $response = $this->actingAs($this->user, 'sanctum')
            ->getJson('/api/assignments?school_year=2025-2026');

        $response->assertOk()
            ->assertJsonCount(1, 'data.classSections')
            ->assertJsonPath('data.classSections.0.class_section_name', 'Grade 1 - A');
    }

    public function test_index_sorts_sections_by_name(): void
    {
        TeacherClass::query()->create([
            'teacher_id' => $this->teacherMain->id,
            'class_section_id' => $this->sectionB->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'B group',
        ]);

        TeacherClass::query()->create([
            'teacher_id' => $this->teacherAssistant->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'A group',
        ]);

        $response = $this->actingAs($this->user, 'sanctum')
            ->getJson('/api/assignments');

        $response->assertOk();

        $sections = $response->json('data.classSections');

        $this->assertCount(2, $sections);
        $this->assertSame('Grade 1 - A', $sections[0]['class_section_name']);
        $this->assertSame('Grade 2 - B', $sections[1]['class_section_name']);
    }

    public function test_index_excludes_inactive_students(): void
    {
        $inactiveStudent = Student::factory()->create([
            'firstname' => 'Hidden',
            'lastname' => 'Student',
            'is_active' => 0,
        ]);

        TeacherClass::query()->create([
            'teacher_id' => $this->teacherMain->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Morning group',
        ]);

        StudentClass::query()->create([
            'student_id' => $inactiveStudent->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Should not show',
            'updated_by' => $this->user->id,
        ]);

        $response = $this->actingAs($this->user, 'sanctum')
            ->getJson('/api/assignments');

        $response->assertOk()
            ->assertJsonPath('data.classSections.0.students', []);
    }

    public function test_store_creates_new_assignment(): void
    {
        $payload = [
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'New assignment',
        ];

        $response = $this->actingAs($this->user, 'sanctum')
            ->postJson('/api/assignments', $payload);

        $response->assertCreated()
            ->assertJsonPath('message', 'Assignment saved successfully.')
            ->assertJsonPath('data.student_id', $this->studentOne->id)
            ->assertJsonPath('data.class_section_id', $this->sectionA->class_section_id)
            ->assertJsonPath('data.semester', 'Fall')
            ->assertJsonPath('data.school_year', '2025-2026')
            ->assertJsonPath('data.description', 'New assignment');

        $this->assertDatabaseHas('student_class', [
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'New assignment',
            'updated_by' => $this->user->id,
        ]);
    }

    public function test_store_updates_existing_assignment_for_same_unique_keys(): void
    {
        StudentClass::query()->create([
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Old description',
            'updated_by' => $this->user->id,
        ]);

        $payload = [
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Updated description',
        ];

        $response = $this->actingAs($this->user, 'sanctum')
            ->postJson('/api/assignments', $payload);

        $response->assertCreated()
            ->assertJsonPath('data.description', 'Updated description');

        $this->assertDatabaseHas('student_class', [
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Updated description',
        ]);

        $this->assertSame(
            1,
            StudentClass::query()
                ->where('student_id', $this->studentOne->id)
                ->where('class_section_id', $this->sectionA->class_section_id)
                ->where('semester', 'Fall')
                ->where('school_year', '2025-2026')
                ->count()
        );
    }

    public function test_store_validates_required_fields(): void
    {
        $response = $this->actingAs($this->user, 'sanctum')
            ->postJson('/api/assignments', []);

        $response->assertUnprocessable()
            ->assertJsonValidationErrors([
                'student_id',
                'class_section_id',
                'semester',
                'school_year',
            ]);
    }

    public function test_store_validates_foreign_keys(): void
    {
        $payload = [
            'student_id' => 999999,
            'class_section_id' => 999999,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Bad ids',
        ];

        $response = $this->actingAs($this->user, 'sanctum')
            ->postJson('/api/assignments', $payload);

        $response->assertUnprocessable()
            ->assertJsonValidationErrors([
                'student_id',
                'class_section_id',
            ]);
    }

    public function test_class_assignment_data_returns_expected_structure(): void
    {
        TeacherClass::query()->create([
            'teacher_id' => $this->teacherMain->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Morning group',
        ]);

        StudentClass::query()->create([
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Morning group',
            'updated_by' => $this->user->id,
        ]);

        $response = $this->actingAs($this->user, 'sanctum')
            ->getJson('/api/assignments/class-assignment-data');

        $response->assertOk()
            ->assertJsonPath('message', 'Class assignment data retrieved successfully.')
            ->assertJsonPath('data.semester', 'Fall')
            ->assertJsonPath('data.school_year', '2025-2026')
            ->assertJsonCount(1, 'data.classSections')
            ->assertJsonPath('data.classSections.0.class_section_name', 'Grade 1 - A')
            ->assertJsonPath('data.classSections.0.main_teachers.0', 'Main Teacher')
            ->assertJsonPath('data.classSections.0.students.0.firstname', 'Ali');
    }

    public function test_class_assignment_data_deduplicates_teacher_names(): void
    {
        TeacherClass::query()->create([
            'teacher_id' => $this->teacherMain->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Morning group',
        ]);

        TeacherClass::query()->create([
            'teacher_id' => $this->teacherMain->id,
            'class_section_id' => $this->sectionA->class_section_id,
            'position' => 'main',
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Morning group',
        ]);

        $response = $this->actingAs($this->user, 'sanctum')
            ->getJson('/api/assignments/class-assignment-data');

        $response->assertOk();

        $mainTeachers = $response->json('data.classSections.0.main_teachers');

        $this->assertSame(['Main Teacher'], $mainTeachers);
    }
}