<?php

namespace Modules\Configuration\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Database\Factories\DivisionRuleFactory;

class DivisionRule extends Model
{
    use HasFactory;

    protected $fillable = [
        'academic_year_id',
        'division',
        'min_points',
        'max_points',
    ];

    protected function casts(): array
    {
        return [
            'min_points' => 'integer',
            'max_points' => 'integer',
        ];
    }

    /**
     * Create a new factory instance for the model.
     */
    protected static function newFactory()
    {
        return DivisionRuleFactory::new();
    }

    /**
     * Get the academic year this division rule belongs to
     */
    public function academicYear(): BelongsTo
    {
        return $this->belongsTo(\Modules\Academic\Models\AcademicYear::class);
    }

    /**
     * Scope to get division rules for a specific academic year
     */
    public function scopeForAcademicYear($query, $academicYearId)
    {
        return $query->where('academic_year_id', $academicYearId);
    }

    /**
     * Get the division for given total points in a specific academic year
     */
    public static function getDivisionForPoints(int $totalPoints, int $academicYearId): ?string
    {
        $rule = static::forAcademicYear($academicYearId)
            ->where('min_points', '<=', $totalPoints)
            ->where('max_points', '>=', $totalPoints)
            ->first();

        // If no exact rule found, try to find the best fit based on percentage
        if (!$rule) {
            // Get all rules for this academic year ordered by min_points desc
            $rules = static::forAcademicYear($academicYearId)
                ->orderBy('min_points', 'desc')
                ->get();

            if ($rules->isNotEmpty()) {
                $highestRule = $rules->first();

                // If points exceed the highest rule's max, give the highest division
                if ($totalPoints > $highestRule->max_points) {
                    return $highestRule->division;
                }

                // If points are below the lowest rule's min, give the lowest division
                $lowestRule = $rules->last();
                if ($totalPoints < $lowestRule->min_points) {
                    return $lowestRule->division;
                }
            }
        }

        return $rule?->division;
    }

    /**
     * Get all division rules for an academic year ordered by min_points asc
     */
    public static function getRulesForAcademicYear(int $academicYearId)
    {
        return static::forAcademicYear($academicYearId)
            ->orderBy('min_points', 'asc')
            ->get();
    }
}
