<?php

namespace Modules\Configuration\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class UpdateGradingRuleRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return $this->user()->role === 'admin';
    }

    /**
     * Get the validation rules that apply to the request.
     */
    public function rules(): array
    {
        $gradingRule = $this->route('grading_rule');

        return [
            'academic_year_id' => [
                'required',
                'integer',
                'exists:academic_years,id'
            ],
            'grade' => [
                'required',
                'string',
                'max:10',
                'regex:/^[A-F][+-]?$/'
            ],
            'min_marks' => [
                'required',
                'numeric',
                'min:0',
                'max:100',
                'lt:max_marks'
            ],
            'max_marks' => [
                'required',
                'numeric',
                'min:0',
                'max:100',
                'gt:min_marks'
            ],
            'points' => [
                'required',
                'numeric',
                'min:0',
                'max:10'
            ],
            'description' => [
                'nullable',
                'string',
                'max:255'
            ],
        ];
    }

    /**
     * Get custom error messages for validator errors.
     */
    public function messages(): array
    {
        return [
            'academic_year_id.required' => 'Academic year is required.',
            'academic_year_id.exists' => 'The selected academic year does not exist.',
            'grade.required' => 'Grade is required.',
            'grade.regex' => 'Grade must be in format A, B, C, D, F with optional + or - (e.g., A+, B-, C).',
            'min_marks.required' => 'Minimum marks is required.',
            'min_marks.min' => 'Minimum marks cannot be negative.',
            'min_marks.max' => 'Minimum marks cannot exceed 100.',
            'min_marks.lt' => 'Minimum marks must be less than maximum marks.',
            'max_marks.required' => 'Maximum marks is required.',
            'max_marks.min' => 'Maximum marks cannot be negative.',
            'max_marks.max' => 'Maximum marks cannot exceed 100.',
            'max_marks.gt' => 'Maximum marks must be greater than minimum marks.',
            'points.required' => 'Points are required.',
            'points.min' => 'Points cannot be negative.',
            'points.max' => 'Points cannot exceed 10.',
        ];
    }

    /**
     * Configure the validator instance.
     */
    public function withValidator($validator)
    {
        $validator->after(function ($validator) {
            $gradingRule = $this->route('grading_rule');

            // Check if academic year is active
            if ($this->academic_year_id) {
                $academicYear = \Modules\Academic\Models\AcademicYear::find($this->academic_year_id);
                if ($academicYear && !$academicYear->is_active) {
                    $validator->errors()->add('academic_year_id', 'Cannot update grading rules for inactive academic year.');
                }
            }

            // Check for duplicate grade in the same academic year (excluding current rule)
            if ($this->academic_year_id && $this->grade) {
                $duplicateExists = \Modules\Configuration\Models\GradingRule::where('id', '!=', $gradingRule->id)
                    ->where('academic_year_id', $this->academic_year_id)
                    ->where('grade', $this->grade)
                    ->exists();

                if ($duplicateExists) {
                    $validator->errors()->add('grade', 'A grading rule with this grade already exists for the selected academic year.');
                }
            }

            // Check for overlapping marks ranges in the same academic year (excluding current rule)
            if ($this->academic_year_id && $this->min_marks !== null && $this->max_marks !== null) {
                $overlappingExists = \Modules\Configuration\Models\GradingRule::where('id', '!=', $gradingRule->id)
                    ->where('academic_year_id', $this->academic_year_id)
                    ->where(function ($query) {
                        $query->whereBetween('min_marks', [$this->min_marks, $this->max_marks])
                            ->orWhereBetween('max_marks', [$this->min_marks, $this->max_marks])
                            ->orWhere(function ($subQuery) {
                                $subQuery->where('min_marks', '<=', $this->min_marks)
                                    ->where('max_marks', '>=', $this->max_marks);
                            });
                    })
                    ->exists();

                if ($overlappingExists) {
                    $validator->errors()->add('min_marks', 'The marks range overlaps with an existing grading rule.');
                    $validator->errors()->add('max_marks', 'The marks range overlaps with an existing grading rule.');
                }
            }

            // Check if grading rule is being used in results
            if ($gradingRule->academic_year_id !== $this->academic_year_id ||
                $gradingRule->min_marks !== $this->min_marks ||
                $gradingRule->max_marks !== $this->max_marks) {

                $hasResults = \Modules\Results\Models\Result::whereHas('enrollment.classroom', function ($query) use ($gradingRule) {
                    $query->where('academic_year_id', $gradingRule->academic_year_id);
                })->exists();

                if ($hasResults) {
                    $validator->errors()->add('academic_year_id', 'Cannot modify grading rule that is being used in existing results.');
                    $validator->errors()->add('min_marks', 'Cannot modify marks range for grading rule with existing results.');
                    $validator->errors()->add('max_marks', 'Cannot modify marks range for grading rule with existing results.');
                }
            }

            // Validate logical grade progression (higher grades should have higher points)
            if ($this->academic_year_id && $this->grade && $this->points !== null) {
                $existingRules = \Modules\Configuration\Models\GradingRule::where('id', '!=', $gradingRule->id)
                    ->where('academic_year_id', $this->academic_year_id)
                    ->get();

                foreach ($existingRules as $rule) {
                    // Simple grade comparison (A > B > C > D > F)
                    $gradeOrder = ['F' => 1, 'D' => 2, 'C' => 3, 'B' => 4, 'A' => 5];
                    $currentGradeBase = substr($this->grade, 0, 1);
                    $existingGradeBase = substr($rule->grade, 0, 1);

                    if (isset($gradeOrder[$currentGradeBase]) && isset($gradeOrder[$existingGradeBase])) {
                        if ($gradeOrder[$currentGradeBase] > $gradeOrder[$existingGradeBase] && $this->points <= $rule->points) {
                            $validator->errors()->add('points', "Grade {$this->grade} should have more points than grade {$rule->grade}.");
                        } elseif ($gradeOrder[$currentGradeBase] < $gradeOrder[$existingGradeBase] && $this->points >= $rule->points) {
                            $validator->errors()->add('points', "Grade {$this->grade} should have fewer points than grade {$rule->grade}.");
                        }
                    }
                }
            }
        });
    }

    /**
     * Prepare the data for validation.
     */
    protected function prepareForValidation()
    {
        $this->merge([
            'grade' => strtoupper($this->grade ?? ''),
        ]);
    }
}
