<?php

namespace Tests\Feature\Api\Administrator;

use App\Models\Configuration;
use App\Models\Enrollment;
use App\Models\Invoice;
use App\Models\Refund;
use App\Models\Student;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;

class AdministratorEnrollmentUpdateStatusesApiTest extends TestCase
{
    use RefreshDatabase;

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

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

    public function test_update_statuses_requires_enrollment_status_payload(): void
    {
        $admin = User::factory()->create();
        Sanctum::actingAs($admin);

        $response = $this->postUpdateStatuses([]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['enrollment_status']);
    }

    public function test_update_statuses_rejects_invalid_status_value(): void
    {
        $admin = User::factory()->create();
        Sanctum::actingAs($admin);

        $response = $this->postUpdateStatuses(['not-valid']);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['enrollment_status.0']);
    }

    public function test_update_statuses_creates_new_enrollment_row(): void
    {
        Event::fake();

        $admin = User::factory()->create(['id' => 900]);
        Sanctum::actingAs($admin);

        $parent = User::factory()->create([
            'id' => 100,
            'firstname' => 'Parent',
            'lastname' => 'One',
            'email' => 'parent1@test.com',
        ]);

        Student::factory()->create([
            'id' => 10,
            'parent_id' => $parent->id,
            'firstname' => 'Ali',
            'lastname' => 'Ben',
        ]);

        $response = $this->postUpdateStatuses([
            10 => 'enrolled',
        ]);

        $response->assertOk()
            ->assertJson([
                'message' => 'Enrollment statuses updated and notifications sent.',
            ]);

        $this->assertDatabaseHas('enrollments', [
            'student_id' => 10,
            'parent_id' => 100,
            'school_year' => '2025-2026',
            'semester' => 'Fall',
            'enrollment_status' => 'enrolled',
            'admission_status' => 'accepted',
            'is_withdrawn' => 0,
        ]);
    }

    public function test_update_statuses_updates_existing_enrollment_row(): void
    {
        Event::fake();

        $admin = User::factory()->create(['id' => 901]);
        Sanctum::actingAs($admin);

        $parent = User::factory()->create([
            'id' => 101,
            'firstname' => 'Parent',
            'lastname' => 'Two',
            'email' => 'parent2@test.com',
        ]);

        Student::factory()->create([
            'id' => 11,
            'parent_id' => $parent->id,
            'firstname' => 'Sara',
            'lastname' => 'Ali',
        ]);

        Enrollment::unguard();
        Enrollment::query()->create([
            'student_id' => 11,
            'parent_id' => 101,
            'school_year' => '2025-2026',
            'semester' => 'Fall',
            'enrollment_status' => 'payment pending',
            'admission_status' => 'accepted',
            'is_withdrawn' => 0,
            'enrollment_date' => now()->toDateString(),
        ]);

        $response = $this->postUpdateStatuses([
            11 => 'withdrawn',
        ]);

        $response->assertOk();

        $this->assertDatabaseHas('enrollments', [
            'student_id' => 11,
            'parent_id' => 101,
            'school_year' => '2025-2026',
            'enrollment_status' => 'withdrawn',
            'admission_status' => 'pending',
        ]);
    }

    public function test_update_statuses_creates_or_updates_refund_when_status_is_refund_pending(): void
    {
        Event::fake();

        $admin = User::factory()->create(['id' => 902]);
        Sanctum::actingAs($admin);

        $parent = User::factory()->create([
            'id' => 102,
            'firstname' => 'Parent',
            'lastname' => 'Three',
            'email' => 'parent3@test.com',
        ]);

        Student::factory()->create([
            'id' => 12,
            'parent_id' => $parent->id,
            'firstname' => 'Mina',
            'lastname' => 'K',
        ]);

        Enrollment::unguard();
        Enrollment::query()->create([
            'student_id' => 12,
            'parent_id' => 102,
            'school_year' => '2025-2026',
            'semester' => 'Fall',
            'enrollment_status' => 'enrolled',
            'admission_status' => 'accepted',
            'is_withdrawn' => 0,
            'enrollment_date' => now()->toDateString(),
        ]);

        Invoice::unguard();
        $invoice = Invoice::query()->create([
            'parent_id' => 102,
            'school_year' => '2025-2026',
            'invoice_number' => 'INV-REF-1',
            'balance' => 125.00,
            'total_amount' => 125.00,
            'issue_date' => now()->toDateString(),
            'due_date' => now()->addDays(10)->toDateString(),
        ]);

        $response = $this->postUpdateStatuses([
            12 => 'refund pending',
        ]);

        $response->assertOk();

        $this->assertDatabaseHas('enrollments', [
            'student_id' => 12,
            'parent_id' => 102,
            'school_year' => '2025-2026',
            'enrollment_status' => 'refund pending',
        ]);

        $this->assertDatabaseHas('refunds', [
            'parent_id' => 102,
            'invoice_id' => $invoice->id,
            'status' => 'Pending',
            'updated_by' => 902,
        ]);

        $refund = Refund::query()->where('invoice_id', $invoice->id)->first();
        $this->assertNotNull($refund);
        $this->assertGreaterThanOrEqual(0, (float) $refund->refund_amount);
    }

    public function test_update_statuses_returns_partial_success_when_some_students_are_invalid_for_processing(): void
    {
        Event::fake();

        $admin = User::factory()->create(['id' => 903]);
        Sanctum::actingAs($admin);

        $parent = User::factory()->create([
            'id' => 103,
            'firstname' => 'Parent',
            'lastname' => 'Four',
            'email' => 'parent4@test.com',
        ]);

        Student::factory()->create([
            'id' => 13,
            'parent_id' => $parent->id,
            'firstname' => 'Adam',
            'lastname' => 'Q',
        ]);

        Student::factory()->create([
            'id' => 14,
            'parent_id' => 0,
            'firstname' => 'No',
            'lastname' => 'Parent',
        ]);

        $response = $this->postUpdateStatuses([
            13 => 'enrolled',
            14 => 'enrolled',
        ]);

        $response->assertStatus(207);

        $this->assertDatabaseHas('enrollments', [
            'student_id' => 13,
            'parent_id' => 103,
            'school_year' => '2025-2026',
            'enrollment_status' => 'enrolled',
        ]);

        $this->assertDatabaseMissing('enrollments', [
            'student_id' => 14,
            'school_year' => '2025-2026',
        ]);
    }

    private function postUpdateStatuses(array $enrollmentStatus)
    {
        $query = http_build_query(['enrollment_status' => $enrollmentStatus]);
        return $this->post('/api/v1/administrator/enrollment-withdrawal/update-statuses?' . $query, []);
    }
}
