<?php

namespace Database\Seeders;

use App\Models\Exam;
use App\Models\Mark;
use App\Models\SchoolClass;
use App\Models\Student;
use App\Models\Subject;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

/**
 * Seeds a ready-to-explore examination so the Exams / Marks / Result Cards /
 * Gazette / Position Holders screens have real data to show.
 *
 * Safe to re-run: it clears its own previous sample exam first (matched by name).
 */
class SampleExamSeeder extends Seeder
{
    public function run(): void
    {
        $branchId = SchoolClass::min('branch_id') ?? \App\Models\Branch::min('id');
        $sessionId = \App\Models\AcademicSession::current()?->id;

        // Core subjects examined (fall back to whatever exists).
        $subjectNames = ['English', 'Urdu', 'Mathematics', 'General Science', 'Islamiat'];
        $subjects = Subject::whereIn('name', $subjectNames)->get();
        if ($subjects->isEmpty()) {
            $subjects = Subject::limit(5)->get();
        }

        // Classes that have active students — pick up to 4 of the smaller ones so
        // the sample stays light but spans several classes for the gazette.
        $classes = SchoolClass::withCount(['students' => fn ($q) => $q->where('status', 'active')])
            ->having('students_count', '>', 0)
            ->orderBy('students_count')
            ->limit(4)->get();

        if ($classes->isEmpty() || $subjects->isEmpty()) {
            $this->command?->warn('SampleExamSeeder: need classes with active students and subjects. Nothing seeded.');

            return;
        }

        $name = 'Mid-Term Examination '.now()->year.' (Sample)';

        DB::transaction(function () use ($name, $branchId, $sessionId, $classes, $subjects) {
            // Remove any previous run of this sample.
            Exam::withTrashed()->where('name', $name)->get()->each(function ($e) {
                $e->marks()->delete();
                $e->papers()->delete();
                $e->forceDelete();
            });

            $exam = Exam::create([
                'branch_id' => $branchId,
                'academic_session_id' => $sessionId,
                'name' => $name,
                'type' => 'mid_term',
                'start_date' => now()->subDays(10)->toDateString(),
                'end_date' => now()->subDays(3)->toDateString(),
                'is_published' => true,
            ]);

            $paperCount = 0;
            $markCount = 0;
            $day = 0;

            foreach ($classes as $class) {
                $students = Student::where('class_id', $class->id)
                    ->where('status', 'active')->get();

                foreach ($subjects as $subject) {
                    $exam->papers()->create([
                        'branch_id' => $branchId,
                        'class_id' => $class->id,
                        'subject_id' => $subject->id,
                        'total_marks' => 100,
                        'passing_marks' => 40,
                        'exam_date' => now()->subDays(10 - ($day % 8))->toDateString(),
                    ]);
                    $paperCount++;
                    $day++;

                    foreach ($students as $student) {
                        // ~4% absent; otherwise a believable spread (a few fails, most pass).
                        $absent = random_int(1, 100) <= 4;
                        $marks = $absent ? null : $this->realisticMark();

                        Mark::create([
                            'branch_id' => $branchId,
                            'exam_id' => $exam->id,
                            'student_id' => $student->id,
                            'class_id' => $class->id,
                            'subject_id' => $subject->id,
                            'obtained_marks' => $marks,
                            'is_absent' => $absent,
                        ]);
                        $markCount++;
                    }
                }
            }

            $this->command?->info("SampleExamSeeder: '{$name}' — {$classes->count()} classes, {$paperCount} papers, {$markCount} marks.");
        });
    }

    /** A believable obtained-marks value out of 100 (skewed toward passing). */
    private function realisticMark(): int
    {
        $roll = random_int(1, 100);

        return match (true) {
            $roll <= 10 => random_int(20, 39),   // 10% fail
            $roll <= 45 => random_int(40, 60),   // 35% average
            $roll <= 80 => random_int(61, 80),   // 35% good
            default => random_int(81, 98),        // 20% excellent
        };
    }
}
