<?php

namespace Database\Seeders;

use App\Enums\Gender;
use App\Enums\Semester;
use App\Enums\StudentStatus;
use App\Models\AcademicTerm;
use App\Models\Department;
use App\Models\Lecturer;
use App\Models\Student;
use App\Models\User;
use App\Models\UserProfile;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class UserSeeder extends Seeder
{
    public function run(): void
    {
        $users = [
            [
                'username' => 'pangestu',
                'email' => 'project.pangestuyoga@gmail.com',
                'roles' => ['developer'],
                'profile' => [
                    'full_name' => 'Yoga Pangestu',
                    'phone_number' => '082121495806',
                    'gender' => Gender::Male,
                    'birth_place' => 'Subang',
                    'birth_date' => '2005-03-13',
                    'address' => 'Jl. Raya Cijambe No. 123, Subang, Jawa Barat',
                ],
            ],
            [
                'username' => 'administrator',
                'email' => 'administrator@gmail.com',
                'roles' => ['staff-admin'],
                'profile' => [
                    'full_name' => 'Administrator',
                    'phone_number' => '082121212121',
                    'gender' => Gender::Male,
                    'birth_place' => 'Purwakarta',
                    'birth_date' => '2000-01-01',
                    'address' => 'Jl. Merdeka No. 1, Purwakarta',
                ],
            ],
        ];

        foreach ($users as $userData) {
            $roles = $userData['roles'];
            $profile = $userData['profile'];

            unset($userData['profile'], $userData['roles']);

            $student = $userData['student'] ?? null;
            $lecturer = $userData['lecturer'] ?? null;

            unset($userData['profile'], $userData['student'], $userData['lecturer']);

            $userData['password'] = Hash::make(config('app.default_password'));

            $user = User::create($userData);
            $user->profile()->create($profile);

            $user->assignRole($roles);

            if ($lecturer) {
                $departmentId = $lecturer['department_id'];
                unset($lecturer['department_id']);

                $createdLecturer = $user->lecturer()->create($lecturer);
                $createdLecturer->departments()->attach($departmentId);
            }

            if ($student) {
                $user->student()->create($student);
            }
        }

        if (app()->environment('local')) {
            $this->seedRandomLecturers();
            $this->seedRandomStudents();
            $this->seedOtherStaff();
        }
    }

    /**
     * 5-8 dosen acak per jurusan. Sebagian dosen diafiliasikan ke lebih dari
     * satu jurusan lewat pivot lecturer_department, sebagian cukup 1 jurusan.
     */
    private function seedRandomLecturers(): void
    {
        $departments = Department::all();

        foreach ($departments as $department) {
            $count = fake()->numberBetween(5, 8);
            $lecturers = collect();

            for ($i = 0; $i < $count; $i++) {
                $lecturer = $this->createLecturer($department);
                $lecturers->push($lecturer);

                if (fake()->boolean(35)) {
                    $otherDepartmentIds = Department::query()
                        ->where('id', '!=', $department->id)
                        ->inRandomOrder()
                        ->limit(fake()->numberBetween(1, 2))
                        ->pluck('id');

                    $lecturer->departments()->attach($otherDepartmentIds);
                }
            }

            $lecturers->random()->user->assignRole('kaprodi');
        }
    }

    private function createLecturer(Department $department): Lecturer
    {
        $user = User::factory()->create();
        $user->profile()->save(UserProfile::factory()->make());
        $user->assignRole('dosen');

        $lecturer = $user->lecturer()->save(Lecturer::factory()->makeOne());

        $lecturer->departments()->attach($department->id);

        return $lecturer;
    }

    /**
     * 8-10 mahasiswa acak per jurusan untuk setiap periode akademik, supaya
     * enrollment_year-nya mengikuti tahun ajaran yang benar-benar ada.
     */
    private function seedRandomStudents(): void
    {
        $departments = Department::all();

        foreach (AcademicTerm::all() as $term) {
            [$startYear, $endYear] = explode('/', $term->academic_year);
            $enrollmentYear = $term->semester === Semester::even ? (int) $endYear : (int) $startYear;

            foreach ($departments as $department) {
                $count = fake()->numberBetween(8, 10);

                for ($i = 0; $i < $count; $i++) {
                    $this->createStudent($department, $enrollmentYear);
                }
            }
        }
    }

    private function createStudent(Department $department, int $enrollmentYear): Student
    {
        $user = User::factory()->create();
        $user->profile()->save(UserProfile::factory()->make());
        $user->assignRole('mahasiswa');

        $advisorId = Lecturer::query()
            ->whereRelation('departments', 'departments.id', $department->id)
            ->inRandomOrder()
            ->value('id');

        $status = fake()->randomElement([
            StudentStatus::Active,
            StudentStatus::Active,
            StudentStatus::Active,
            StudentStatus::OnLeave,
            StudentStatus::Graduated,
            StudentStatus::DroppedOut,
        ]);

        return $user->student()->save(Student::factory()->makeOne([
            'department_id' => $department->id,
            'enrollment_year' => $enrollmentYear,
            'academic_advisor_id' => $advisorId,
            'status' => $status,
        ]));
    }

    /**
     * Sejumlah kecil akun staf lain supaya tiap role punya data acak juga.
     */
    private function seedOtherStaff(): void
    {
        $roleCounts = [
            'staff-admin' => 2,
            'staff-keuangan' => 2,
            'developer' => 2,
        ];

        foreach ($roleCounts as $role => $count) {
            for ($i = 0; $i < $count; $i++) {
                $user = User::factory()->create();
                $user->profile()->save(UserProfile::factory()->make());
                $user->assignRole($role);
            }
        }
    }
}
