<?php

namespace Tests\Unit\Services;

use App\Models\CertificateRecord;
use App\Models\ClassSection;
use App\Models\Configuration;
use App\Models\Student;
use App\Models\StudentClass;
use App\Models\StudentDecision;
use App\Models\User;
use App\Services\Certificates\CertificateAdminService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class CertificateAdminServiceTest extends TestCase
{
    use RefreshDatabase;

    private CertificateAdminService $service;

    private string $schoolYear = '2025-2026';

    private ClassSection $section;

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

        Configuration::query()->create([
            'config_key' => 'school_year',
            'config_value' => $this->schoolYear,
        ]);

        $this->section = ClassSection::factory()->create([
            'class_section_id' => 501,
            'class_section_name' => 'Grade 5-A',
        ]);

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

    public function test_dashboard_groups_students_and_uses_saved_decisions_as_source_of_truth(): void
    {
        $passStudent = $this->enrollStudent('Amina', 'Pass', 'Female');
        $repeatStudent = $this->enrollStudent('Bilal', 'Repeat', 'Male');
        $pendingStudent = $this->enrollStudent('Celine', 'Pending', 'Female');

        StudentDecision::query()->create([
            'student_id' => $passStudent->id,
            'school_year' => $this->schoolYear,
            'class_section_name' => $this->section->class_section_name,
            'year_score' => 95.50,
            'decision' => 'Pass',
            'source' => 'manual',
        ]);

        StudentDecision::query()->create([
            'student_id' => $repeatStudent->id,
            'school_year' => $this->schoolYear,
            'class_section_name' => $this->section->class_section_name,
            'year_score' => 58.25,
            'decision' => 'Repeat Class',
            'source' => 'manual',
        ]);

        CertificateRecord::query()->create([
            'certificate_number' => 'ARSS-2025-2026-0001',
            'verification_token' => 'existingtoken',
            'student_id' => $passStudent->id,
            'student_name' => 'Amina Pass',
            'grade' => 'Grade 5',
            'cert_date' => '2026-06-05',
            'school_year' => $this->schoolYear,
            'class_section_id' => $this->section->class_section_id,
            'issued_at' => now(),
        ]);

        $payload = $this->service->dashboard($this->schoolYear);

        $this->assertSame($this->schoolYear, $payload['school_year']);
        $this->assertCount(1, $payload['grade_groups']);
        $this->assertSame('Grade 5', $payload['grade_groups'][0]['label']);
        $this->assertTrue($payload['grade_groups'][0]['has_pass']);
        $this->assertTrue($payload['grade_groups'][0]['fully_done']);

        $section = $payload['grade_groups'][0]['sections'][0];
        $this->assertSame(3, $section['student_count']);
        $this->assertSame(1, $section['pass_count']);
        $this->assertSame(1, $section['cert_count']);
        $this->assertSame(0, $section['remaining_count']);

        $students = collect($section['students'])->keyBy('student_id');

        $this->assertTrue($students[$passStudent->id]['eligible']);
        $this->assertSame(['Pass'], $students[$passStudent->id]['decision_labels']);
        $this->assertSame('ARSS-2025-2026-0001', $students[$passStudent->id]['certificate_number']);

        $this->assertFalse($students[$repeatStudent->id]['eligible']);
        $this->assertSame(['Repeat Class'], $students[$repeatStudent->id]['decision_labels']);

        $this->assertFalse($students[$pendingStudent->id]['eligible']);
        $this->assertSame('pending', $students[$pendingStudent->id]['decision_state']);
    }

    public function test_issue_certificates_reuses_existing_record_and_creates_new_one_for_unissued_pass_students(): void
    {
        $admin = User::factory()->create();
        $existingStudent = $this->enrollStudent('Adam', 'Existing', 'Male');
        $newStudent = $this->enrollStudent('Dina', 'New', 'Female');

        foreach ([$existingStudent, $newStudent] as $student) {
            StudentDecision::query()->create([
                'student_id' => $student->id,
                'school_year' => $this->schoolYear,
                'class_section_name' => $this->section->class_section_name,
                'year_score' => 90.00,
                'decision' => 'Pass',
                'source' => 'manual',
            ]);
        }

        CertificateRecord::query()->create([
            'certificate_number' => 'ARSS-2025-2026-0001',
            'verification_token' => 'persistedtoken',
            'student_id' => $existingStudent->id,
            'student_name' => 'Adam Existing',
            'grade' => 'Grade 5',
            'cert_date' => '2026-06-05',
            'school_year' => $this->schoolYear,
            'class_section_id' => $this->section->class_section_id,
            'issued_by' => $admin->id,
            'issued_at' => now(),
        ]);

        $payload = $this->service->issueCertificates(
            [$existingStudent->id, $newStudent->id],
            '06/05/2026',
            $this->section->class_section_id,
            $this->schoolYear,
            $admin->id
        );

        $this->assertSame('06/05/2026', $payload['cert_date_display']);
        $this->assertCount(2, $payload['students']);

        $issued = collect($payload['students'])->keyBy('id');

        $this->assertSame('ARSS-2025-2026-0001', $issued[$existingStudent->id]['cert_number']);
        $this->assertNotSame('', $issued[$existingStudent->id]['verify_token']);
        $this->assertSame('ARSS-2025-2026-0002', $issued[$newStudent->id]['cert_number']);
        $this->assertNotSame('', $issued[$newStudent->id]['verify_token']);

        $this->assertSame(2, CertificateRecord::query()->where('school_year', $this->schoolYear)->count());

        $newRecord = CertificateRecord::query()
            ->where('student_id', $newStudent->id)
            ->where('school_year', $this->schoolYear)
            ->first();

        $this->assertNotNull($newRecord);
        $this->assertSame('Grade 5', $newRecord->grade);
        $this->assertSame('2026-06-05', $newRecord->cert_date?->format('Y-m-d'));
        $this->assertSame($admin->id, $newRecord->issued_by);
    }

    public function test_audit_log_returns_year_summary_and_filtered_records(): void
    {
        CertificateRecord::query()->create([
            'certificate_number' => 'ARSS-2025-2026-0001',
            'verification_token' => 'token-a',
            'student_id' => 1,
            'student_name' => 'Ali One',
            'grade' => 'Grade 5',
            'cert_date' => '2026-06-05',
            'school_year' => '2025-2026',
            'issued_at' => now(),
        ]);

        CertificateRecord::query()->create([
            'certificate_number' => 'ARSS-2024-2025-0001',
            'verification_token' => 'token-b',
            'student_id' => 2,
            'student_name' => 'Maya Two',
            'grade' => 'Grade 4',
            'cert_date' => '2025-06-01',
            'school_year' => '2024-2025',
            'issued_at' => now()->subDay(),
        ]);

        $payload = $this->service->auditLog('2025-2026');

        $this->assertSame('2025-2026', $payload['school_year']);
        $this->assertCount(1, $payload['records']);
        $this->assertSame('ARSS-2025-2026-0001', $payload['records'][0]['certificate_number']);
        $this->assertCount(2, $payload['year_summary']);
    }

    private function enrollStudent(string $firstname, string $lastname, string $gender): Student
    {
        $student = Student::factory()->create([
            'firstname' => $firstname,
            'lastname' => $lastname,
            'gender' => $gender,
            'school_year' => $this->schoolYear,
            'is_active' => 1,
        ]);

        StudentClass::query()->create([
            'student_id' => $student->id,
            'class_section_id' => $this->section->class_section_id,
            'school_year' => $this->schoolYear,
            'semester' => 'Spring',
            'is_event_only' => 0,
        ]);

        return $student;
    }
}
