<?php

namespace Tests\Concerns;

use App\Models\Role;
use App\Models\SchoolYear;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Testing\TestResponse;

/**
 * Reusable deterministic fixtures for end-to-end API scenario tests.
 *
 * @see docs/alrahma_end_to_end_use_case_test_plan.md Part III
 */
trait SeedsE2ETestFixtures
{
    use CreatesApiTestUsers;

    protected const E2E_SCHOOL_YEAR = '2025-2026';
    protected const E2E_PREV_SCHOOL_YEAR = '2024-2025';
    protected const E2E_SEMESTER = 'Fall';

    protected function seedE2EConfiguration(): void
    {
        // Pin calendar context so semester-aware services resolve to Fall 2025-2026.
        $this->travelTo('2025-10-05 10:00:00');

        $this->seedApiTestConfig(self::E2E_SCHOOL_YEAR, self::E2E_SEMESTER);

        DB::table('configuration')->updateOrInsert(
            ['config_key' => 'fall_semester_start'],
            ['config_value' => '2025-09-01']
        );
        DB::table('configuration')->updateOrInsert(
            ['config_key' => 'spring_semester_start'],
            ['config_value' => '2026-01-15']
        );
        DB::table('configuration')->updateOrInsert(
            ['config_key' => 'last_school_day'],
            ['config_value' => '2026-06-15']
        );
    }

    protected function seedClosedSchoolYear(): void
    {
        SchoolYear::query()->updateOrCreate(
            ['name' => self::E2E_PREV_SCHOOL_YEAR],
            [
                'start_date' => '2024-09-01',
                'end_date' => '2025-06-30',
                'status' => SchoolYear::STATUS_CLOSED,
                'is_current' => false,
            ]
        );
    }

    protected function seedClassSection(
        int $classSectionId = 701,
        string $name = '5A',
        int $classId = 5
    ): int {
        DB::table('classSection')->insert([
            'class_id' => $classId,
            'class_section_id' => $classSectionId,
            'class_section_name' => $name,
            'semester' => self::E2E_SEMESTER,
            'school_year' => self::E2E_SCHOOL_YEAR,
        ]);

        return $classSectionId;
    }

    protected function seedTeacherClassAssignment(int $teacherId, int $classSectionId, string $position = 'main'): void
    {
        DB::table('teacher_class')->insert([
            'teacher_id' => $teacherId,
            'class_section_id' => $classSectionId,
            'position' => $position,
            'school_year' => self::E2E_SCHOOL_YEAR,
            'semester' => self::E2E_SEMESTER,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    protected function seedStudentClassAssignment(int $studentId, int $classSectionId): void
    {
        DB::table('student_class')->insert([
            'student_id' => $studentId,
            'class_section_id' => $classSectionId,
            'school_year' => self::E2E_SCHOOL_YEAR,
            'semester' => self::E2E_SEMESTER,
            'is_event_only' => 0,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    /**
     * @return array{teacher: User, class_section_id: int, student_id: int, parent_id: int}
     */
    protected function seedTeacherClassWithStudent(?int $classSectionId = null): array
    {
        $this->seedE2EConfiguration();
        $classSectionId ??= $this->seedClassSection(801, '3A', 3);

        $teacher = $this->createApiUserWithRole('teacher', [
            'firstname' => 'Tara',
            'lastname' => 'Teacher',
            'email' => 'e2e.teacher.' . uniqid('', true) . '@example.test',
        ]);
        $this->seedTeacherClassAssignment($teacher->id, $classSectionId);

        $parent = $this->createApiUserWithRole('parent', [
            'firstname' => 'Parent',
            'lastname' => 'Fixture',
            'email' => 'e2e.parent.' . uniqid('', true) . '@example.test',
        ]);

        $studentId = DB::table('students')->insertGetId([
            'school_id' => 'S-E2E-' . random_int(1000, 9999),
            'firstname' => 'Kai',
            'lastname' => 'Student',
            'dob' => '2014-09-01',
            'age' => 11,
            'gender' => 'Male',
            'photo_consent' => 1,
            'parent_id' => $parent->id,
            'year_of_registration' => '2025',
            'school_year' => self::E2E_SCHOOL_YEAR,
            'semester' => self::E2E_SEMESTER,
            'is_active' => 1,
        ]);
        $this->seedStudentClassAssignment($studentId, $classSectionId);

        return [
            'teacher' => $teacher,
            'class_section_id' => $classSectionId,
            'student_id' => $studentId,
            'parent_id' => $parent->id,
            'parent' => $parent,
        ];
    }

    protected function createParentAccountViaApi(array $overrides = []): int
    {
        $parentRoleId = (int) Role::query()->where('name', 'parent')->value('id');
        $unique = str_replace('.', '', uniqid('', true));

        $payload = array_merge([
            'firstname' => 'E2E',
            'lastname' => 'Parent',
            'gender' => 'Female',
            'cellphone' => '5551234567',
            'email' => "e2e.parent.$unique@example.test",
            'address_street' => '42 Cedar Lane',
            'city' => 'Brooklyn',
            'state' => 'NY',
            'zip' => '11201',
            'accept_school_policy' => true,
            'role_id' => $parentRoleId,
            'password' => 'secret123',
            'semester' => self::E2E_SEMESTER,
            'school_year' => self::E2E_SCHOOL_YEAR,
            'user_type' => 'primary',
            'status' => 'Active',
            'is_verified' => true,
        ], $overrides);

        $response = $this->postJson('/api/v1/users', $payload);
        $response->assertStatus(201)->assertJsonPath('ok', true);

        return (int) $response->json('user_id');
    }

    protected function createStudentViaApi(int $parentId, array $overrides = [], bool $firstChild = true): int
    {
        $unique = str_replace('.', '', uniqid('', true));
        $payload = array_merge([
            'firstname' => 'E2E',
            'lastname' => 'Student',
            'dob' => '2015-05-10',
            'age' => 10,
            'gender' => 'Male',
            'is_active' => true,
            'registration_grade' => '5',
            'is_new' => true,
            'photo_consent' => true,
            'parent_id' => $parentId,
            'registration_date' => '2025-09-01',
            'tuition_paid' => false,
            'semester' => self::E2E_SEMESTER,
            'year_of_registration' => 2025,
            'school_year' => self::E2E_SCHOOL_YEAR,
        ], $overrides);

        if ($firstChild) {
            $payload = array_merge($payload, [
                'name' => $overrides['name'] ?? 'E2E Parent',
                'cellphone' => $overrides['cellphone'] ?? '5551234567',
                'email' => $overrides['email'] ?? "e2e.contact.$unique@example.test",
                'relation' => $overrides['relation'] ?? 'Mother',
            ]);
        }

        $response = $this->postJson('/api/v1/students', $payload);
        $response->assertStatus(201)->assertJsonPath('ok', true);

        return (int) $response->json('student.id');
    }

    protected function assignStudentToClassViaApi(int $studentId, int $classSectionId): TestResponse
    {
        return $this->postJson('/api/v1/students/assign-class', [
            'student_id' => $studentId,
            'class_section_id' => [$classSectionId],
        ]);
    }

    protected function postEnrollmentStatuses(array $studentStatusMap): TestResponse
    {
        return $this->post(
            '/api/v1/administrator/enrollment-withdrawal/update-statuses?' .
            http_build_query(['enrollment_status' => $studentStatusMap]),
            []
        );
    }

    protected function seedInvoiceForParent(int $parentId, array $overrides = []): int
    {
        return DB::table('invoices')->insertGetId(array_merge([
            'parent_id' => $parentId,
            'invoice_number' => 'INV-E2E-' . random_int(1000, 9999),
            'total_amount' => 500.00,
            'balance' => 500.00,
            'paid_amount' => 0,
            'has_discount' => 0,
            'issue_date' => '2025-09-01',
            'due_date' => '2025-10-01',
            'status' => 'unpaid',
            'school_year' => self::E2E_SCHOOL_YEAR,
            'semester' => self::E2E_SEMESTER,
            'created_at' => now(),
            'updated_at' => now(),
        ], $overrides));
    }

    protected function seedPriorYearUnpaidInvoice(int $parentId): int
    {
        return DB::table('invoices')->insertGetId([
            'parent_id' => $parentId,
            'invoice_number' => 'INV-PRIOR-' . random_int(1000, 9999),
            'total_amount' => 200.00,
            'balance' => 150.00,
            'paid_amount' => 50.00,
            'has_discount' => 0,
            'issue_date' => '2024-09-01',
            'due_date' => '2024-10-01',
            'status' => 'unpaid',
            'school_year' => self::E2E_PREV_SCHOOL_YEAR,
            'semester' => self::E2E_SEMESTER,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    protected function seedDiscountVoucher(): int
    {
        return DB::table('discount_vouchers')->insertGetId([
            'code' => 'E2E10-' . random_int(100, 999),
            'discount_type' => 'fixed',
            'discount_value' => 50,
            'max_uses' => 100,
            'times_used' => 0,
            'is_active' => 1,
        ]);
    }
}
