<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use App\Models\User;
use Modules\Students\Models\Student;
use Modules\Teachers\Models\Teacher;
use Modules\Guardians\Models\Guardian;
use Modules\Academic\Models\AcademicYear;
use Modules\Academic\Models\Subject;
use Modules\Academic\Models\Classroom;
use Modules\Academic\Models\ExamType;
use Modules\Enrollment\Models\Enrollment;
use Modules\Results\Models\Result;
use Modules\Configuration\Models\GradingRule;
use Modules\Configuration\Models\DivisionRule;

class SchoolManagementSystemTest extends TestCase
{
    use RefreshDatabase, WithFaker;

    protected $admin;
    protected $academicYear;
    protected $subject;
    protected $classroom;
    protected $examType;
    protected $student;
    protected $teacher;
    protected $guardian;

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

        // Create test data
        $this->admin = User::factory()->create([
            'role' => 'admin',
            'email' => 'admin@test.com'
        ]);

        $this->academicYear = AcademicYear::create([
            'name' => '2024-2025',
            'start_date' => '2024-09-01',
            'end_date' => '2025-06-30',
            'is_active' => true,
        ]);

        $this->subject = Subject::create([
            'name' => 'Mathematics',
            'code' => 'MATH',
            'description' => 'Mathematics subject',
            'is_active' => true,
        ]);

        $this->classroom = Classroom::create([
            'academic_year_id' => $this->academicYear->id,
            'name' => 'Form 1A',
            'capacity' => 30,
            'description' => 'Test classroom',
        ]);

        $this->examType = ExamType::create([
            'academic_year_id' => $this->academicYear->id,
            'name' => 'Midterm Exam',
            'weight' => 30.00,
            'description' => 'Midterm examination',
            'is_active' => true,
        ]);

        // Create student with user
        $studentUser = User::factory()->create(['role' => 'student']);
        $this->student = Student::create([
            'user_id' => $studentUser->id,
            'student_id' => 'STU0001',
            'first_name' => 'John',
            'last_name' => 'Doe',
            'date_of_birth' => '2008-01-01',
            'gender' => 'male',
            'address' => '123 Test Street',
            'phone' => '555-0001',
            'emergency_contact' => '555-0002',
            'admission_date' => '2024-01-01',
            'is_active' => true,
        ]);

        // Create teacher with user
        $teacherUser = User::factory()->create(['role' => 'teacher']);
        $this->teacher = Teacher::create([
            'user_id' => $teacherUser->id,
            'teacher_id' => 'TCH0001',
            'first_name' => 'Jane',
            'last_name' => 'Smith',
            'date_of_birth' => '1985-01-01',
            'gender' => 'female',
            'address' => '456 Teacher Lane',
            'phone' => '555-0003',
            'qualification' => 'Master',
            'hire_date' => '2020-01-01',
            'is_active' => true,
        ]);

        // Create guardian with user
        $guardianUser = User::factory()->create(['role' => 'guardian']);
        $this->guardian = Guardian::create([
            'user_id' => $guardianUser->id,
            'first_name' => 'Bob',
            'last_name' => 'Doe',
            'phone' => '555-0004',
            'address' => '789 Guardian Ave',
            'occupation' => 'Engineer',
            'is_active' => true,
        ]);
    }

    /** @test */
    public function admin_can_access_dashboard()
    {
        $response = $this->actingAs($this->admin)
            ->get('/dashboard');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) => $page->component('Dashboard'));
    }

    /** @test */
    public function admin_can_view_students_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/students');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Students/Index')
                ->has('students.data')
                ->has('filters')
                ->has('academicYears')
                ->has('classrooms')
        );
    }

    /** @test */
    public function admin_can_create_student()
    {
        $studentData = [
            'first_name' => 'Test',
            'last_name' => 'Student',
            'email' => 'test.student@example.com',
            'student_id' => 'STU9999',
            'date_of_birth' => '2008-01-01',
            'gender' => 'male',
            'address' => '123 Test Street',
            'phone' => '555-9999',
            'emergency_contact' => '555-8888',
            'admission_date' => '2024-01-01',
        ];

        $response = $this->actingAs($this->admin)
            ->post('/students', $studentData);

        $response->assertRedirect('/students');
        $this->assertDatabaseHas('students', [
            'student_id' => 'STU9999',
            'first_name' => 'Test',
            'last_name' => 'Student',
        ]);
    }

    /** @test */
    public function admin_can_update_student()
    {
        $updateData = [
            'first_name' => 'Updated',
            'last_name' => 'Student',
            'email' => $this->student->user->email,
            'student_id' => $this->student->student_id,
            'date_of_birth' => $this->student->date_of_birth->format('Y-m-d'),
            'gender' => $this->student->gender,
            'address' => 'Updated Address',
            'phone' => $this->student->phone,
            'emergency_contact' => $this->student->emergency_contact,
            'admission_date' => $this->student->admission_date->format('Y-m-d'),
        ];

        $response = $this->actingAs($this->admin)
            ->put("/students/{$this->student->id}", $updateData);

        $response->assertRedirect('/students');
        $this->assertDatabaseHas('students', [
            'id' => $this->student->id,
            'first_name' => 'Updated',
            'address' => 'Updated Address',
        ]);
    }

    /** @test */
    public function admin_can_delete_student()
    {
        $response = $this->actingAs($this->admin)
            ->delete("/students/{$this->student->id}");

        $response->assertRedirect('/students');
        $this->assertSoftDeleted('students', ['id' => $this->student->id]);
    }

    /** @test */
    public function admin_can_view_teachers_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/teachers');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Teachers/Index')
                ->has('teachers.data')
                ->has('filters')
                ->has('subjects')
        );
    }

    /** @test */
    public function admin_can_create_teacher()
    {
        $teacherData = [
            'first_name' => 'Test',
            'last_name' => 'Teacher',
            'email' => 'test.teacher@example.com',
            'teacher_id' => 'TCH9999',
            'date_of_birth' => '1985-01-01',
            'gender' => 'female',
            'address' => '123 Teacher Street',
            'phone' => '555-9999',
            'qualification' => 'PhD',
            'hire_date' => '2024-01-01',
            'subject_ids' => [$this->subject->id],
        ];

        $response = $this->actingAs($this->admin)
            ->post('/teachers', $teacherData);

        $response->assertRedirect('/teachers');
        $this->assertDatabaseHas('teachers', [
            'teacher_id' => 'TCH9999',
            'first_name' => 'Test',
            'last_name' => 'Teacher',
        ]);
    }

    /** @test */
    public function admin_can_view_guardians_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/guardians');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Guardians/Index')
                ->has('guardians.data')
                ->has('filters')
        );
    }

    /** @test */
    public function admin_can_create_guardian()
    {
        $guardianData = [
            'first_name' => 'Test',
            'last_name' => 'Guardian',
            'email' => 'test.guardian@example.com',
            'phone' => '555-9999',
            'address' => '123 Guardian Street',
            'occupation' => 'Doctor',
        ];

        $response = $this->actingAs($this->admin)
            ->post('/guardians', $guardianData);

        $response->assertRedirect('/guardians');
        $this->assertDatabaseHas('guardians', [
            'first_name' => 'Test',
            'last_name' => 'Guardian',
            'occupation' => 'Doctor',
        ]);
    }

    /** @test */
    public function admin_can_view_academic_years_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/academic-years');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Academic/AcademicYears/Index')
                ->has('academicYears.data')
                ->has('filters')
        );
    }

    /** @test */
    public function admin_can_create_academic_year()
    {
        $academicYearData = [
            'name' => '2025-2026',
            'start_date' => '2025-09-01',
            'end_date' => '2026-06-30',
            'is_active' => false,
        ];

        $response = $this->actingAs($this->admin)
            ->post('/academic-years', $academicYearData);

        $response->assertRedirect('/academic-years');
        $this->assertDatabaseHas('academic_years', [
            'name' => '2025-2026',
            'start_date' => '2025-09-01',
        ]);
    }

    /** @test */
    public function admin_can_view_subjects_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/subjects');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Academic/Subjects/Index')
                ->has('subjects.data')
                ->has('filters')
        );
    }

    /** @test */
    public function admin_can_create_subject()
    {
        $subjectData = [
            'name' => 'Physics',
            'code' => 'PHY',
            'description' => 'Physics subject',
            'is_active' => true,
        ];

        $response = $this->actingAs($this->admin)
            ->post('/subjects', $subjectData);

        $response->assertRedirect('/subjects');
        $this->assertDatabaseHas('subjects', [
            'name' => 'Physics',
            'code' => 'PHY',
        ]);
    }

    /** @test */
    public function admin_can_view_classrooms_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/classrooms');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Academic/Classrooms/Index')
                ->has('classrooms.data')
                ->has('filters')
                ->has('academicYears')
        );
    }

    /** @test */
    public function admin_can_create_classroom()
    {
        $classroomData = [
            'academic_year_id' => $this->academicYear->id,
            'name' => 'Form 2A',
            'capacity' => 25,
            'description' => 'Test classroom 2A',
            'subject_ids' => [$this->subject->id],
        ];

        $response = $this->actingAs($this->admin)
            ->post('/classrooms', $classroomData);

        $response->assertRedirect('/classrooms');
        $this->assertDatabaseHas('classrooms', [
            'name' => 'Form 2A',
            'capacity' => 25,
        ]);
    }

    /** @test */
    public function admin_can_view_exam_types_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/exam-types');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Academic/ExamTypes/Index')
                ->has('examTypes.data')
                ->has('statistics')
                ->has('filters')
        );
    }

    /** @test */
    public function admin_can_create_exam_type()
    {
        $examTypeData = [
            'academic_year_id' => $this->academicYear->id,
            'name' => 'Final Exam',
            'weight' => 50.00,
            'description' => 'Final examination',
            'is_active' => true,
        ];

        $response = $this->actingAs($this->admin)
            ->post('/exam-types', $examTypeData);

        $response->assertRedirect('/exam-types');
        $this->assertDatabaseHas('exam_types', [
            'name' => 'Final Exam',
            'weight' => 50.00,
        ]);
    }

    /** @test */
    public function admin_can_view_enrollment_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/enrollment');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Enrollment/Index')
                ->has('enrollments.data')
                ->has('filters')
                ->has('academicYears')
                ->has('classrooms')
        );
    }

    /** @test */
    public function admin_can_create_enrollment()
    {
        $enrollmentData = [
            'student_id' => $this->student->id,
            'classroom_id' => $this->classroom->id,
            'academic_year_id' => $this->academicYear->id,
            'enrolled_at' => '2024-01-01',
            'is_active' => true,
        ];

        $response = $this->actingAs($this->admin)
            ->post('/enrollment', $enrollmentData);

        $response->assertRedirect();
        $this->assertDatabaseHas('enrollments', [
            'student_id' => $this->student->id,
            'classroom_id' => $this->classroom->id,
            'academic_year_id' => $this->academicYear->id,
        ]);
    }

    /** @test */
    public function admin_can_view_results_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/results');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Results/Index')
                ->has('results.data')
                ->has('filters')
                ->has('academicYears')
                ->has('examTypes')
                ->has('subjects')
                ->has('classrooms')
        );
    }

    /** @test */
    public function admin_can_create_result()
    {
        // First create an enrollment
        $enrollment = Enrollment::create([
            'student_id' => $this->student->id,
            'classroom_id' => $this->classroom->id,
            'academic_year_id' => $this->academicYear->id,
            'enrolled_at' => now(),
            'is_active' => true,
        ]);

        $resultData = [
            'student_id' => $this->student->id,
            'subject_id' => $this->subject->id,
            'classroom_id' => $this->classroom->id,
            'academic_year_id' => $this->academicYear->id,
            'exam_type_id' => $this->examType->id,
            'marks' => 85,
            'grade' => 'A',
            'points' => 11,
        ];

        $response = $this->actingAs($this->admin)
            ->post('/results', $resultData);

        $response->assertRedirect('/results');
        $this->assertDatabaseHas('results', [
            'student_id' => $this->student->id,
            'subject_id' => $this->subject->id,
            'marks' => 85,
        ]);
    }

    /** @test */
    public function admin_can_view_configuration_index()
    {
        $response = $this->actingAs($this->admin)
            ->get('/configuration');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) => $page->component('Configuration/Index'));
    }

    /** @test */
    public function admin_can_view_grading_rules()
    {
        $response = $this->actingAs($this->admin)
            ->get('/configuration/grading-rules');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Configuration/GradingRules')
                ->has('gradingRules.data')
                ->has('statistics')
                ->has('filters')
                ->has('academicYears')
        );
    }

    /** @test */
    public function admin_can_create_grading_rule()
    {
        $gradingRuleData = [
            'academic_year_id' => $this->academicYear->id,
            'grade' => 'A+',
            'min_marks' => 90,
            'max_marks' => 100,
            'points' => 12,
        ];

        $response = $this->actingAs($this->admin)
            ->post('/configuration/grading-rules', $gradingRuleData);

        $response->assertRedirect('/configuration/grading-rules');
        $this->assertDatabaseHas('grading_rules', [
            'academic_year_id' => $this->academicYear->id,
            'grade' => 'A+',
            'min_marks' => 90,
            'max_marks' => 100,
            'points' => 12,
        ]);
    }

    /** @test */
    public function admin_can_view_division_rules()
    {
        $response = $this->actingAs($this->admin)
            ->get('/configuration/division-rules');

        $response->assertStatus(200);
        $response->assertInertia(fn ($page) =>
            $page->component('Configuration/DivisionRules')
                ->has('divisionRules.data')
                ->has('statistics')
                ->has('filters')
                ->has('academicYears')
        );
    }

    /** @test */
    public function admin_can_create_division_rule()
    {
        $divisionRuleData = [
            'academic_year_id' => $this->academicYear->id,
            'division' => 'First Class',
            'min_points' => 8.0,
            'max_points' => 12.0,
        ];

        $response = $this->actingAs($this->admin)
            ->post('/configuration/division-rules', $divisionRuleData);

        $response->assertRedirect('/configuration/division-rules');
        $this->assertDatabaseHas('division_rules', [
            'academic_year_id' => $this->academicYear->id,
            'division' => 'First Class',
            'min_points' => 8.0,
            'max_points' => 12.0,
        ]);
    }
}
