<?php

namespace Tests\Unit\Services;

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 App\Services\AssignmentService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AssignmentServiceTest extends TestCase
{
    use RefreshDatabase;

    protected AssignmentService $service;
    protected User $teacherMain;
    protected User $teacherAssistant;
    protected User $updatedByUser;
    protected ClassSection $sectionA;
    protected ClassSection $sectionB;
    protected Student $studentOne;
    protected Student $studentTwo;

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

        $this->service = app(AssignmentService::class);

        Configuration::query()->create([
            'config_key' => 'semester',
            'config_value' => 'Fall',
        ]);

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

        $this->updatedByUser = User::factory()->create();

        $this->teacherMain = User::factory()->create([
            'firstname' => 'John',
            'lastname' => 'Doe',
        ]);

        $this->teacherAssistant = User::factory()->create([
            'firstname' => 'Jane',
            'lastname' => 'Smith',
        ]);

        $this->sectionA = ClassSection::factory()->create([
            'section_name' => 'Alpha Section',
        ]);

        $this->sectionB = ClassSection::factory()->create([
            'section_name' => 'Beta Section',
        ]);

        $this->studentOne = Student::factory()->create([
            'firstname' => 'Ali',
            'lastname' => 'One',
            'age' => 10,
            'gender' => 'Male',
            'registration_grade' => 'Grade 4',
            'photo_consent' => 1,
            'tuition_paid' => 0,
            'school_id' => 'S-100',
            'is_active' => 1,
        ]);

        $this->studentTwo = Student::factory()->create([
            'firstname' => 'Maya',
            'lastname' => 'Two',
            'age' => 11,
            'gender' => 'Female',
            'registration_grade' => 'Grade 5',
            'photo_consent' => 0,
            'tuition_paid' => 1,
            'school_id' => 'S-101',
            'is_active' => 1,
        ]);
    }

    public function test_get_current_semester_returns_config_value(): void
    {
        $this->assertSame('Fall', $this->service->getCurrentSemester());
    }

    public function test_get_current_school_year_returns_config_value(): void
    {
        $this->assertSame('2025-2026', $this->service->getCurrentSchoolYear());
    }

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

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

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

        $result = $this->service->getAssignmentsOverview('2025-2026', 'Fall');

        $this->assertSame('2025-2026', $result['schoolYear']);
        $this->assertSame('2025-2026', $result['selectedYear']);
        $this->assertSame('Fall', $result['selectedSemester']);
        $this->assertSame('Fall', $result['semester']);
        $this->assertSame('2025-2026', $result['current_school_year']);
        $this->assertCount(1, $result['classSections']);

        $section = $result['classSections'][0];

        $this->assertSame($this->sectionA->id, $section['class_section_id']);
        $this->assertSame('Alpha Section', $section['class_section_name']);
        $this->assertSame(['John Doe'], $section['main_teachers']);
        $this->assertSame(['Jane Smith'], $section['teacher_assistants']);
        $this->assertSame('Fall', $section['semester']);
        $this->assertSame('2025-2026', $section['school_year']);
        $this->assertSame('Alpha description', $section['description']);
        $this->assertCount(1, $section['students']);
        $this->assertSame('Ali', $section['students'][0]['firstname']);
    }

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

        $result = $this->service->getAssignmentsOverview();

        $section = $result['classSections'][0];

        $this->assertSame('Fall', $section['semester']);
        $this->assertSame('2025-2026', $section['school_year']);
        $this->assertSame('', $section['description']);
    }

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

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

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

        $result = $this->service->getAssignmentsOverview();

        $section = $result['classSections'][0];

        $this->assertSame([], $section['students']);
    }

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

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

        $result = $this->service->getAssignmentsOverview();

        $this->assertCount(2, $result['classSections']);
        $this->assertSame('Alpha Section', $result['classSections'][0]['class_section_name']);
        $this->assertSame('Beta Section', $result['classSections'][1]['class_section_name']);
    }

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

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

        $result = $this->service->getAssignmentsOverview();

        $this->assertSame(['2025-2026', '2024-2025'], array_values($result['schoolYears']));
    }

    public function test_store_assignment_creates_new_row(): void
    {
        $assignment = $this->service->storeAssignment([
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Created by service',
        ], $this->updatedByUser->id);

        $this->assertInstanceOf(StudentClass::class, $assignment);
        $this->assertDatabaseHas('student_class', [
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'Created by service',
            'updated_by' => $this->updatedByUser->id,
        ]);
    }

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

        $assignment = $this->service->storeAssignment([
            'student_id' => $this->studentOne->id,
            'class_section_id' => $this->sectionA->id,
            'semester' => 'Fall',
            'school_year' => '2025-2026',
            'description' => 'New',
        ], $this->updatedByUser->id);

        $this->assertSame('New', $assignment->description);

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

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

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

        TeacherClass::query()->create([
            'teacher_id' => $this->teacherAssistant->id,
            'class_section_id' => $this->sectionB->id,
            'position' => 'ta',
            'semester' => 'Spring',
            'school_year' => '2025-2026',
            'description' => 'Beta description',
        ]);

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

        StudentClass::query()->create([
            'student_id' => $this->studentTwo->id,
            'class_section_id' => $this->sectionB->id,
            'semester' => 'Spring',
            'school_year' => '2025-2026',
            'description' => 'Beta description',
            'updated_by' => $this->updatedByUser->id,
        ]);

        $result = $this->service->getClassAssignmentData();

        $this->assertSame('Fall', $result['semester']);
        $this->assertSame('2025-2026', $result['school_year']);
        $this->assertCount(2, $result['classSections']);
        $this->assertSame('Alpha Section', $result['classSections'][0]['class_section_name']);
        $this->assertSame('Beta Section', $result['classSections'][1]['class_section_name']);
    }

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

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

        $result = $this->service->getClassAssignmentData();

        $this->assertSame(
            ['John Doe'],
            $result['classSections'][0]['main_teachers']
        );
    }
}
