<?php

namespace App\Http\Requests\Admin\Manage;

use App\Enums\ClassMethod;
use App\Enums\Semester;
use App\Models\AcademicTerm;
use App\Models\Course;
use App\Models\Lecturer;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class CourseClassRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can($this->isMethod('post') ? 'create-course-classes' : 'update-course-classes');
    }

    public function rules(): array
    {
        $academicTermId = $this->input('academic_term_id');
        $academicTerm = $academicTermId ? AcademicTerm::find($academicTermId) : null;

        $semesterParityRule = function ($attribute, $value, $fail) use ($academicTerm) {
            if (! $academicTerm) {
                return;
            }

            $semesterNumber = Course::find($value)?->semester_number;

            if ($semesterNumber === null) {
                return;
            }

            $isOddSemester = $semesterNumber % 2 === 1;
            $matches = $academicTerm->semester === Semester::odd ? $isOddSemester : ! $isOddSemester;

            if (! $matches) {
                $fail('Mata kuliah semester '.$semesterNumber.' tidak sesuai dengan periode '.$academicTerm->semester->label().'.');
            }
        };

        if ($this->isMethod('post')) {
            return [
                'course_ids' => ['required', 'array', 'min:1'],
                'course_ids.*' => [
                    'integer',
                    Rule::exists('courses', 'id'),
                    Rule::unique('course_classes', 'course_id')
                        ->where('academic_term_id', $academicTermId)
                        ->whereNull('deleted_at'),
                    $semesterParityRule,
                ],
                'lecturer_id' => [
                    'required',
                    'integer',
                    function ($attribute, $value, $fail) {
                        $courseIds = (array) $this->input('course_ids', []);
                        $departmentIds = Course::whereIn('id', $courseIds)->pluck('department_id')->unique();
                        $lecturer = Lecturer::find($value);
                        $coveredDepartmentIds = $lecturer
                            ? $lecturer->departments()->pluck('departments.id')
                            : collect();

                        if ($departmentIds->diff($coveredDepartmentIds)->isNotEmpty()) {
                            $fail('Dosen tidak terdaftar di jurusan seluruh mata kuliah yang dipilih.');
                        }
                    },
                ],
                'academic_term_id' => ['required', 'integer', Rule::exists('academic_terms', 'id')],
                'method' => ['nullable', 'string', Rule::enum(ClassMethod::class)],
            ];
        }

        $departmentId = Course::find($this->input('course_id'))?->department_id;

        return [
            'course_id' => [
                'required',
                'integer',
                Rule::exists('courses', 'id'),
                Rule::unique('course_classes', 'course_id')
                    ->where('academic_term_id', $academicTermId)
                    ->whereNull('deleted_at')
                    ->ignore($this->route('course_class')?->id),
                $semesterParityRule,
            ],
            'lecturer_id' => [
                'required',
                'integer',
                Rule::exists('lecturer_department', 'lecturer_id')->where('department_id', $departmentId),
            ],
            'academic_term_id' => ['required', 'integer', Rule::exists('academic_terms', 'id')],
            'method' => ['nullable', 'string', Rule::enum(ClassMethod::class)],
        ];
    }
}
