<?php

namespace Modules\Configuration\Http\Requests;

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

class StoreDivisionRuleRequest 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
    {
        return [
            'academic_year_id' => [
                'required',
                'integer',
                'exists:academic_years,id'
            ],
            'division' => [
                'required',
                'string',
                'max:50',
                'regex:/^[A-Za-z\s\d]+$/'
            ],
            'min_points' => [
                'required',
                'numeric',
                'min:0',
                'max:10',
                'lt:max_points'
            ],
            'max_points' => [
                'required',
                'numeric',
                'min:0',
                'max:10',
                'gt:min_points'
            ],
            '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.',
            'division.required' => 'Division name is required.',
            'division.regex' => 'Division name can only contain letters and spaces.',
            'min_points.required' => 'Minimum points are required.',
            'min_points.min' => 'Minimum points cannot be negative.',
            'min_points.max' => 'Minimum points cannot exceed 10.',
            'min_points.lt' => 'Minimum points must be less than maximum points.',
            'max_points.required' => 'Maximum points are required.',
            'max_points.min' => 'Maximum points cannot be negative.',
            'max_points.max' => 'Maximum points cannot exceed 10.',
            'max_points.gt' => 'Maximum points must be greater than minimum points.',
        ];
    }

    /**
     * Configure the validator instance.
     */
    public function withValidator($validator)
    {
        $validator->after(function ($validator) {
            // 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 create division rules for inactive academic year.');
                }
            }

            // Check for duplicate division in the same academic year
            if ($this->academic_year_id && $this->division) {
                $duplicateExists = \Modules\Configuration\Models\DivisionRule::where('academic_year_id', $this->academic_year_id)
                    ->where('division', $this->division)
                    ->exists();

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

            // Check for overlapping points ranges in the same academic year
            if ($this->academic_year_id && $this->min_points !== null && $this->max_points !== null) {
                $overlappingExists = \Modules\Configuration\Models\DivisionRule::where('academic_year_id', $this->academic_year_id)
                    ->where(function ($query) {
                        $query->whereBetween('min_points', [$this->min_points, $this->max_points])
                            ->orWhereBetween('max_points', [$this->min_points, $this->max_points])
                            ->orWhere(function ($subQuery) {
                                $subQuery->where('min_points', '<=', $this->min_points)
                                    ->where('max_points', '>=', $this->max_points);
                            });
                    })
                    ->exists();

                if ($overlappingExists) {
                    $validator->errors()->add('min_points', 'The points range overlaps with an existing division rule.');
                    $validator->errors()->add('max_points', 'The points range overlaps with an existing division rule.');
                }
            }

            // Validate logical division progression (better divisions should have higher points)
            if ($this->academic_year_id && $this->division && $this->min_points !== null) {
                $existingRules = \Modules\Configuration\Models\DivisionRule::where('academic_year_id', $this->academic_year_id)
                    ->get();

                // Common division hierarchy (lower number = better performance)
                $divisionOrder = [
                    'i' => 1, 'ii' => 2, 'iii' => 3, 'iv' => 4, 'fail' => 5, 'incomplete' => 6
                ];

                $currentDivisionKey = strtolower($this->division);

                foreach ($existingRules as $rule) {
                    $existingDivisionKey = strtolower($rule->division);

                    if (isset($divisionOrder[$currentDivisionKey]) && isset($divisionOrder[$existingDivisionKey])) {
                        if ($divisionOrder[$currentDivisionKey] > $divisionOrder[$existingDivisionKey] &&
                            $this->min_points <= $rule->min_points) {
                            $validator->errors()->add('min_points', "Division '{$this->division}' should have higher minimum points than '{$rule->division}'.");
                        } elseif ($divisionOrder[$currentDivisionKey] < $divisionOrder[$existingDivisionKey] &&
                                 $this->min_points >= $rule->min_points) {
                            $validator->errors()->add('min_points', "Division '{$this->division}' should have lower minimum points than '{$rule->division}'.");
                        }
                    }
                }
            }

            // Ensure there are corresponding grading rules for the academic year
            if ($this->academic_year_id) {
                $hasGradingRules = \Modules\Configuration\Models\GradingRule::where('academic_year_id', $this->academic_year_id)
                    ->exists();

                if (!$hasGradingRules) {
                    $validator->errors()->add('academic_year_id', 'Please create grading rules first before creating division rules.');
                }
            }
        });
    }

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