<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use App\Models\User;
use Modules\Academic\Models\AcademicYear;
use Modules\Academic\Models\Subject;
use Modules\Academic\Models\Classroom;
use Modules\Academic\Models\ExamType;
use Modules\Students\Models\Student;
use Modules\Teachers\Models\Teacher;
use Modules\Guardians\Models\Guardian;
use Modules\Enrollment\Models\Enrollment;
use Modules\Results\Models\Result;
use Modules\Configuration\Models\GradingRule;
use Modules\Configuration\Models\DivisionRule;

class SampleDataSeeder extends Seeder
{
    public function run(): void
    {
        // Disable foreign key checks (SQLite compatible)
        if (DB::getDriverName() === 'mysql') {
            DB::statement('SET FOREIGN_KEY_CHECKS=0;');
        } else {
            DB::statement('PRAGMA foreign_keys=OFF;');
        }

        // Clear existing data
        $this->clearTables();

        // Create sample data
        $this->createUsers();
        $academicYears = $this->createAcademicYears();
        $subjects = $this->createSubjects($academicYears);
        $classrooms = $this->createClassrooms($academicYears, $subjects);
        $examTypes = $this->createExamTypes($academicYears);
        $students = $this->createStudents();
        $teachers = $this->createTeachers();
        $guardians = $this->createGuardians();
        $this->createStudentGuardianRelationships($students, $guardians);
        $this->createEnrollments($students, $classrooms, $academicYears);
        $this->createTeacherSubjectAssignments($teachers, $subjects);
        $this->createResults($students, $subjects, $examTypes, $classrooms, $academicYears);
        $this->createGradingRules($academicYears);
        $this->createDivisionRules($academicYears);

        // Re-enable foreign key checks
        if (DB::getDriverName() === 'mysql') {
            DB::statement('SET FOREIGN_KEY_CHECKS=1;');
        } else {
            DB::statement('PRAGMA foreign_keys=ON;');
        }

        $this->command->info('Sample data created successfully!');
    }

    private function clearTables(): void
    {
        // Clear in reverse dependency order
        DB::table('results')->truncate();
        DB::table('teacher_subjects')->truncate();
        DB::table('classroom_subjects')->truncate();
        DB::table('student_guardians')->truncate();
        DB::table('enrollments')->truncate();
        DB::table('division_rules')->truncate();
        DB::table('grading_rules')->truncate();
        DB::table('exam_types')->truncate();
        DB::table('classrooms')->truncate();
        DB::table('subjects')->truncate();
        DB::table('guardians')->truncate();
        DB::table('teachers')->truncate();
        DB::table('students')->truncate();
        DB::table('academic_years')->truncate();
        DB::table('users')->where('email', '!=', 'admin@example.com')->delete();
    }

    private function createUsers(): void
    {
        // Create admin user if not exists
        if (!User::where('email', 'admin@example.com')->exists()) {
            User::create([
                'name' => 'Admin User',
                'email' => 'admin@example.com',
                'password' => Hash::make('password'),
                'role' => 'admin',
                'email_verified_at' => now(),
            ]);
        }
    }

    private function createAcademicYears(): array
    {
        $academicYears = [
            [
                'name' => '2023-2024',
                'start_date' => '2023-09-01',
                'end_date' => '2024-06-30',
                'is_active' => false,
            ],
            [
                'name' => '2024-2025',
                'start_date' => '2024-09-01',
                'end_date' => '2025-06-30',
                'is_active' => true,
            ],
            [
                'name' => '2025-2026',
                'start_date' => '2025-09-01',
                'end_date' => '2026-06-30',
                'is_active' => false,
            ],
        ];

        $created = [];
        foreach ($academicYears as $year) {
            $created[] = AcademicYear::create($year);
        }

        return $created;
    }

    private function createSubjects(array $academicYears): array
    {
        $subjectData = [
            ['name' => 'Mathematics', 'code' => 'MATH'],
            ['name' => 'English Language', 'code' => 'ENG'],
            ['name' => 'Physics', 'code' => 'PHY'],
            ['name' => 'Chemistry', 'code' => 'CHEM'],
            ['name' => 'Biology', 'code' => 'BIO'],
            ['name' => 'History', 'code' => 'HIST'],
            ['name' => 'Geography', 'code' => 'GEO'],
            ['name' => 'Computer Science', 'code' => 'CS'],
            ['name' => 'Art', 'code' => 'ART'],
            ['name' => 'Physical Education', 'code' => 'PE'],
        ];

        $subjects = [];
        foreach ($subjectData as $subject) {
            $subjects[] = Subject::create([
                'name' => $subject['name'],
                'code' => $subject['code'],
                'description' => "Study of {$subject['name']}",
                'is_active' => true,
            ]);
        }

        return $subjects;
    }

    private function createClassrooms(array $academicYears, array $subjects): array
    {
        $classroomData = [
            ['name' => 'Form 1A', 'capacity' => 30],
            ['name' => 'Form 1B', 'capacity' => 32],
            ['name' => 'Form 2A', 'capacity' => 28],
            ['name' => 'Form 2B', 'capacity' => 30],
            ['name' => 'Form 3A', 'capacity' => 25],
            ['name' => 'Form 3B', 'capacity' => 27],
            ['name' => 'Form 4A', 'capacity' => 24],
            ['name' => 'Form 4B', 'capacity' => 26],
        ];

        $classrooms = [];
        foreach ($academicYears as $academicYear) {
            foreach ($classroomData as $classroom) {
                $created = Classroom::create([
                    'academic_year_id' => $academicYear->id,
                    'name' => $classroom['name'],
                    'capacity' => $classroom['capacity'],
                    'description' => "Classroom for {$classroom['name']} in {$academicYear->name}",
                ]);

                // Assign random subjects to classroom
                $randomSubjects = collect($subjects)->random(rand(6, 8));
                $created->subjects()->attach($randomSubjects->pluck('id'));

                $classrooms[] = $created;
            }
        }

        return $classrooms;
    }

    private function createExamTypes(array $academicYears): array
    {
        $examTypeData = [
            ['name' => 'Midterm Exam', 'weight' => 30.00, 'description' => 'Mid-semester examination'],
            ['name' => 'Final Exam', 'weight' => 50.00, 'description' => 'End of semester examination'],
            ['name' => 'Assignment', 'weight' => 10.00, 'description' => 'Course assignments'],
            ['name' => 'Quiz', 'weight' => 10.00, 'description' => 'Regular quizzes'],
        ];

        $examTypes = [];
        foreach ($academicYears as $academicYear) {
            foreach ($examTypeData as $examType) {
                $examTypes[] = ExamType::create([
                    'academic_year_id' => $academicYear->id,
                    'name' => $examType['name'],
                    'weight' => $examType['weight'],
                    'description' => $examType['description'],
                    'is_active' => true,
                ]);
            }
        }

        return $examTypes;
    }

    private function createStudents(): array
    {
        $studentNames = [
            ['John', 'Doe'], ['Jane', 'Smith'], ['Michael', 'Johnson'], ['Emily', 'Brown'],
            ['David', 'Wilson'], ['Sarah', 'Davis'], ['Robert', 'Miller'], ['Lisa', 'Garcia'],
            ['William', 'Rodriguez'], ['Jennifer', 'Martinez'], ['James', 'Anderson'], ['Mary', 'Taylor'],
            ['Christopher', 'Thomas'], ['Patricia', 'Hernandez'], ['Daniel', 'Moore'], ['Linda', 'Martin'],
            ['Matthew', 'Jackson'], ['Barbara', 'Thompson'], ['Anthony', 'White'], ['Susan', 'Lopez'],
            ['Mark', 'Lee'], ['Karen', 'Gonzalez'], ['Steven', 'Harris'], ['Nancy', 'Clark'],
            ['Paul', 'Lewis'], ['Betty', 'Robinson'], ['Andrew', 'Walker'], ['Helen', 'Perez'],
            ['Joshua', 'Hall'], ['Sandra', 'Young'], ['Kenneth', 'Allen'], ['Donna', 'Sanchez'],
            ['Kevin', 'Wright'], ['Carol', 'King'], ['Brian', 'Scott'], ['Ruth', 'Torres'],
            ['George', 'Nguyen'], ['Sharon', 'Hill'], ['Edward', 'Flores'], ['Michelle', 'Green'],
        ];

        $students = [];
        foreach ($studentNames as $index => $name) {
            $user = User::create([
                'name' => $name[0] . ' ' . $name[1],
                'email' => strtolower($name[0] . '.' . $name[1]) . '@student.school.com',
                'password' => Hash::make('password'),
                'role' => 'student',
                'email_verified_at' => now(),
            ]);

            $students[] = Student::create([
                'user_id' => $user->id,
                'student_id' => 'STU' . str_pad($index + 1, 4, '0', STR_PAD_LEFT),
                'first_name' => $name[0],
                'last_name' => $name[1],
                'date_of_birth' => now()->subYears(rand(15, 18))->format('Y-m-d'),
                'gender' => rand(0, 1) ? 'male' : 'female',
                'address' => (100 + $index) . ' Main Street, City, State',
                'phone' => '555-' . str_pad($index + 1000, 4, '0', STR_PAD_LEFT),
                'emergency_contact' => '555-' . str_pad($index + 5000, 4, '0', STR_PAD_LEFT),
                'admission_date' => now()->subMonths(rand(1, 24))->format('Y-m-d'),
                'is_active' => true,
            ]);
        }

        return $students;
    }

    private function createTeachers(): array
    {
        $teacherNames = [
            ['Dr. Alice', 'Johnson'], ['Prof. Robert', 'Williams'], ['Ms. Maria', 'Garcia'],
            ['Mr. David', 'Brown'], ['Dr. Susan', 'Davis'], ['Prof. Michael', 'Miller'],
            ['Ms. Jennifer', 'Wilson'], ['Mr. Christopher', 'Moore'], ['Dr. Lisa', 'Taylor'],
            ['Prof. William', 'Anderson'], ['Ms. Karen', 'Thomas'], ['Mr. Richard', 'Jackson'],
        ];

        $teachers = [];
        foreach ($teacherNames as $index => $name) {
            $user = User::create([
                'name' => $name[0] . ' ' . $name[1],
                'email' => strtolower(str_replace([' ', '.'], '', $name[0]) . '.' . $name[1]) . '@teacher.school.com',
                'password' => Hash::make('password'),
                'role' => 'teacher',
                'email_verified_at' => now(),
            ]);

            $teachers[] = Teacher::create([
                'user_id' => $user->id,
                'teacher_id' => 'TCH' . str_pad($index + 1, 4, '0', STR_PAD_LEFT),
                'first_name' => $name[0],
                'last_name' => $name[1],
                'date_of_birth' => now()->subYears(rand(25, 55))->format('Y-m-d'),
                'gender' => rand(0, 1) ? 'male' : 'female',
                'address' => (200 + $index) . ' Teacher Lane, City, State',
                'phone' => '555-' . str_pad($index + 2000, 4, '0', STR_PAD_LEFT),
                'qualification' => ['Bachelor', 'Master', 'PhD'][rand(0, 2)],
                'hire_date' => now()->subYears(rand(1, 10))->format('Y-m-d'),
                'is_active' => true,
            ]);
        }

        return $teachers;
    }

    private function createGuardians(): array
    {
        $guardianNames = [
            ['Mr. John', 'Doe Sr.'], ['Mrs. Jane', 'Smith'], ['Mr. Michael', 'Johnson Sr.'],
            ['Mrs. Emily', 'Brown'], ['Mr. David', 'Wilson Sr.'], ['Mrs. Sarah', 'Davis'],
            ['Mr. Robert', 'Miller Sr.'], ['Mrs. Lisa', 'Garcia'], ['Mr. William', 'Rodriguez Sr.'],
            ['Mrs. Jennifer', 'Martinez'], ['Mr. James', 'Anderson Sr.'], ['Mrs. Mary', 'Taylor'],
        ];

        $guardians = [];
        foreach ($guardianNames as $index => $name) {
            $user = User::create([
                'name' => $name[0] . ' ' . $name[1],
                'email' => strtolower(str_replace([' ', '.'], '', $name[0]) . '.' . str_replace([' ', '.'], '', $name[1])) . '@guardian.school.com',
                'password' => Hash::make('password'),
                'role' => 'guardian',
                'email_verified_at' => now(),
            ]);

            $guardians[] = Guardian::create([
                'user_id' => $user->id,
                'first_name' => $name[0],
                'last_name' => $name[1],
                'phone' => '555-' . str_pad($index + 3000, 4, '0', STR_PAD_LEFT),
                'address' => (300 + $index) . ' Guardian Avenue, City, State',
                'occupation' => ['Engineer', 'Doctor', 'Teacher', 'Business Owner', 'Lawyer'][rand(0, 4)],
                'is_active' => true,
            ]);
        }

        return $guardians;
    }

    private function createStudentGuardianRelationships(array $students, array $guardians): void
    {
        $relationships = ['father', 'mother', 'guardian', 'uncle', 'aunt', 'grandparent'];

        foreach ($students as $index => $student) {
            // Assign 1-2 guardians to each student
            $studentGuardians = collect($guardians)->random(rand(1, 2));

            foreach ($studentGuardians as $guardianIndex => $guardian) {
                DB::table('student_guardians')->insert([
                    'student_id' => $student->id,
                    'guardian_id' => $guardian->id,
                    'relationship' => $relationships[rand(0, count($relationships) - 1)],
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }
        }
    }

    private function createEnrollments(array $students, array $classrooms, array $academicYears): void
    {
        // Get current academic year classrooms
        $currentYear = collect($academicYears)->where('is_active', true)->first();
        $currentClassrooms = collect($classrooms)->where('academic_year_id', $currentYear->id);

        // Enroll students in current year
        foreach ($students as $index => $student) {
            $classroom = $currentClassrooms->random();

            Enrollment::create([
                'student_id' => $student->id,
                'classroom_id' => $classroom->id,
                'academic_year_id' => $currentYear->id,
                'enrolled_at' => now()->subDays(rand(1, 30)),
                'is_active' => true,
            ]);
        }

        // Create some historical enrollments
        $previousYear = collect($academicYears)->where('is_active', false)->first();
        if ($previousYear) {
            $previousClassrooms = collect($classrooms)->where('academic_year_id', $previousYear->id);

            // Enroll some students in previous year
            foreach (collect($students)->take(20) as $student) {
                $classroom = $previousClassrooms->random();

                Enrollment::create([
                    'student_id' => $student->id,
                    'classroom_id' => $classroom->id,
                    'academic_year_id' => $previousYear->id,
                    'enrolled_at' => $previousYear->start_date,
                    'is_active' => false,
                ]);
            }
        }
    }

    private function createTeacherSubjectAssignments(array $teachers, array $subjects): void
    {
        foreach ($teachers as $teacher) {
            // Assign 2-4 subjects to each teacher
            $assignedSubjects = collect($subjects)->random(rand(2, 4));
            $teacher->subjects()->attach($assignedSubjects->pluck('id'));
        }
    }

    private function createResults(array $students, array $subjects, array $examTypes, array $classrooms, array $academicYears): void
    {
        $currentYear = collect($academicYears)->where('is_active', true)->first();
        $currentExamTypes = collect($examTypes)->where('academic_year_id', $currentYear->id);

        foreach ($students as $student) {
            // Get student's enrollment
            $enrollment = Enrollment::where('student_id', $student->id)
                ->where('academic_year_id', $currentYear->id)
                ->where('is_active', true)
                ->first();

            if (!$enrollment) continue;

            // Get classroom subjects
            $classroomSubjects = $enrollment->classroom->subjects;

            foreach ($classroomSubjects as $subject) {
                foreach ($currentExamTypes as $examType) {
                    // Create results for 80% of combinations (some missing results)
                    if (rand(1, 100) <= 80) {
                        $marks = rand(30, 95); // Random marks between 30-95

                        Result::create([
                            'student_id' => $student->id,
                            'subject_id' => $subject->id,
                            'classroom_id' => $enrollment->classroom_id,
                            'academic_year_id' => $currentYear->id,
                            'exam_type_id' => $examType->id,
                            'marks' => $marks,
                            'grade' => $this->calculateGrade($marks),
                            'points' => $this->calculatePoints($marks),
                            'entered_at' => now()->subDays(rand(1, 60)),
                        ]);
                    }
                }
            }
        }
    }

    private function createGradingRules(array $academicYears): void
    {
        $gradingData = [
            ['grade' => 'A+', 'min_marks' => 90, 'max_marks' => 100, 'points' => 12],
            ['grade' => 'A', 'min_marks' => 80, 'max_marks' => 89, 'points' => 11],
            ['grade' => 'A-', 'min_marks' => 75, 'max_marks' => 79, 'points' => 10],
            ['grade' => 'B+', 'min_marks' => 70, 'max_marks' => 74, 'points' => 9],
            ['grade' => 'B', 'min_marks' => 65, 'max_marks' => 69, 'points' => 8],
            ['grade' => 'B-', 'min_marks' => 60, 'max_marks' => 64, 'points' => 7],
            ['grade' => 'C+', 'min_marks' => 55, 'max_marks' => 59, 'points' => 6],
            ['grade' => 'C', 'min_marks' => 50, 'max_marks' => 54, 'points' => 5],
            ['grade' => 'C-', 'min_marks' => 45, 'max_marks' => 49, 'points' => 4],
            ['grade' => 'D+', 'min_marks' => 40, 'max_marks' => 44, 'points' => 3],
            ['grade' => 'D', 'min_marks' => 35, 'max_marks' => 39, 'points' => 2],
            ['grade' => 'D-', 'min_marks' => 30, 'max_marks' => 34, 'points' => 1],
            ['grade' => 'F', 'min_marks' => 0, 'max_marks' => 29, 'points' => 0],
        ];

        foreach ($academicYears as $academicYear) {
            foreach ($gradingData as $grade) {
                GradingRule::create([
                    'academic_year_id' => $academicYear->id,
                    'grade' => $grade['grade'],
                    'min_marks' => $grade['min_marks'],
                    'max_marks' => $grade['max_marks'],
                    'points' => $grade['points'],
                ]);
            }
        }
    }

    private function createDivisionRules(array $academicYears): void
    {
        $divisionData = [
            ['division' => 'First Class', 'min_points' => 8.0, 'max_points' => 12.0],
            ['division' => 'Second Class', 'min_points' => 6.0, 'max_points' => 7.9],
            ['division' => 'Third Class', 'min_points' => 4.0, 'max_points' => 5.9],
            ['division' => 'Fail', 'min_points' => 0.0, 'max_points' => 3.9],
        ];

        foreach ($academicYears as $academicYear) {
            foreach ($divisionData as $division) {
                DivisionRule::create([
                    'academic_year_id' => $academicYear->id,
                    'division' => $division['division'],
                    'min_points' => $division['min_points'],
                    'max_points' => $division['max_points'],
                ]);
            }
        }
    }

    private function calculateGrade(int $marks): string
    {
        if ($marks >= 90) return 'A+';
        if ($marks >= 80) return 'A';
        if ($marks >= 75) return 'A-';
        if ($marks >= 70) return 'B+';
        if ($marks >= 65) return 'B';
        if ($marks >= 60) return 'B-';
        if ($marks >= 55) return 'C+';
        if ($marks >= 50) return 'C';
        if ($marks >= 45) return 'C-';
        if ($marks >= 40) return 'D+';
        if ($marks >= 35) return 'D';
        if ($marks >= 30) return 'D-';
        return 'F';
    }

    private function calculatePoints(int $marks): int
    {
        if ($marks >= 90) return 12;
        if ($marks >= 80) return 11;
        if ($marks >= 75) return 10;
        if ($marks >= 70) return 9;
        if ($marks >= 65) return 8;
        if ($marks >= 60) return 7;
        if ($marks >= 55) return 6;
        if ($marks >= 50) return 5;
        if ($marks >= 45) return 4;
        if ($marks >= 40) return 3;
        if ($marks >= 35) return 2;
        if ($marks >= 30) return 1;
        return 0;
    }
}
