<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class CreditScoreTier extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'min_score',
        'max_score',
        'base_interest_rate',
        'max_loan_amount',
        'max_loan_term',
        'description',
        'is_active',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'min_score' => 'integer',
        'max_score' => 'integer',
        'base_interest_rate' => 'decimal:2',
        'max_loan_amount' => 'decimal:2',
        'max_loan_term' => 'integer',
        'is_active' => 'boolean',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    /**
     * Scope a query to only include active tiers.
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope a query for a specific credit score.
     */
    public function scopeForScore($query, $score)
    {
        return $query->where('min_score', '<=', $score)
                    ->where('max_score', '>=', $score);
    }

    /**
     * Scope a query to order tiers by score range.
     */
    public function scopeOrdered($query)
    {
        return $query->orderBy('min_score', 'desc');
    }

    /**
     * Get the tier for a specific credit score.
     */
    public static function getTierForScore($score)
    {
        return static::active()
                    ->forScore($score)
                    ->first();
    }

    /**
     * Check if a score falls within this tier's range.
     */
    public function isScoreInRange($score)
    {
        return $score >= $this->min_score && $score <= $this->max_score;
    }

    /**
     * Get tier display name with score range.
     */
    public function getDisplayNameAttribute()
    {
        return "{$this->name} ({$this->min_score}-{$this->max_score})";
    }

    /**
     * Get formatted interest rate.
     */
    public function getFormattedInterestRateAttribute()
    {
        return number_format($this->base_interest_rate, 2) . '%';
    }

    /**
     * Get formatted max loan amount.
     */
    public function getFormattedMaxLoanAmountAttribute()
    {
        return 'ZMW ' . number_format($this->max_loan_amount, 2);
    }

    /**
     * Relationship with loan applications.
     */
    public function loanApplications()
    {
        return $this->hasMany(LoanApplication::class);
    }

    /**
     * Get active tiers for dropdown selection.
     */
    public static function getForDropdown()
    {
        return static::active()
                    ->ordered()
                    ->pluck('name', 'id')
                    ->toArray();
    }

    /**
     * Validate score ranges to ensure no overlaps.
     */
    public static function validateScoreRanges($minScore, $maxScore, $excludeId = null)
    {
        $query = static::where(function($q) use ($minScore, $maxScore) {
            $q->whereBetween('min_score', [$minScore, $maxScore])
              ->orWhereBetween('max_score', [$minScore, $maxScore])
              ->orWhere(function($q) use ($minScore, $maxScore) {
                  $q->where('min_score', '<=', $minScore)
                    ->where('max_score', '>=', $maxScore);
              });
        });

        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        return $query->count() === 0;
    }

    /**
     * Boot method for model events.
     */
    protected static function boot()
    {
        parent::boot();

        static::saving(function ($model) {
            // Ensure min_score is less than max_score
            if ($model->min_score >= $model->max_score) {
                throw new \Exception('Minimum score must be less than maximum score.');
            }

            // Validate no overlapping score ranges
            if (!static::validateScoreRanges($model->min_score, $model->max_score, $model->id)) {
                throw new \Exception('Score range overlaps with existing tier.');
            }
        });
    }
}