<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;

class LoanProduct extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'slug',
        'description',
        'terms_and_conditions',
        'interest_type',
        'interest_rate',
        'interest_rate_display',
        'min_amount',
        'max_amount',
        'default_amount',
        'currency',
        'min_term_months',
        'max_term_months',
        'default_term_months',
        'eligible_categories',
        'min_membership_months',
        'min_contribution_balance',
        'additional_requirements',
        'processing_fee',
        'processing_fee_percentage',
        'late_payment_penalty',
        'is_active',
        'is_featured',
        'requires_collateral',
        'requires_guarantor',
        'min_guarantors',
        'icon',
        'theme_color',
        'sort_order',
        'created_by',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'interest_rate' => 'decimal:2',
        'min_amount' => 'decimal:2',
        'max_amount' => 'decimal:2',
        'default_amount' => 'decimal:2',
        'min_contribution_balance' => 'decimal:2',
        'processing_fee' => 'decimal:2',
        'processing_fee_percentage' => 'decimal:2',
        'late_payment_penalty' => 'decimal:2',
        'eligible_categories' => 'array',
        'additional_requirements' => 'array',
        'min_term_months' => 'integer',
        'max_term_months' => 'integer',
        'default_term_months' => 'integer',
        'min_membership_months' => 'integer',
        'min_guarantors' => 'integer',
        'is_active' => 'boolean',
        'is_featured' => 'boolean',
        'requires_collateral' => 'boolean',
        'requires_guarantor' => 'boolean',
        'sort_order' => 'integer',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    /**
     * The attributes that should be appended.
     *
     * @var array<int, string>
     */
    protected $appends = ['formatted_interest_rate', 'formatted_amount_range'];

    /**
     * Get the loan applications for the product.
     */
    public function loanApplications(): HasMany
    {
        return $this->hasMany(LoanApplication::class);
    }

    /**
     * Get the user who created the product.
     */
    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * Get formatted interest rate.
     */
    public function getFormattedInterestRateAttribute(): string
    {
        return $this->interest_rate . '% ' . $this->interest_rate_display;
    }

    /**
     * Get formatted amount range.
     */
    public function getFormattedAmountRangeAttribute(): string
    {
        $symbols = [
            'USD' => '$',
            'SSP' => '£',
            'KES' => 'KSh',
            'UGX' => 'USh',
        ];

        $symbol = $symbols[$this->currency] ?? $this->currency . ' ';
        return $symbol . number_format($this->min_amount, 0) . ' - ' . $symbol . number_format($this->max_amount, 0);
    }

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

    /**
     * Scope a query to only include featured products.
     */
    public function scopeFeatured($query)
    {
        return $query->where('is_featured', true);
    }

    /**
     * Scope a query to order by sort order.
     */
    public function scopeOrdered($query)
    {
        return $query->orderBy('sort_order')->orderBy('name');
    }

    /**
     * Calculate monthly payment.
     */
    public function calculateMonthlyPayment(float $principal, int $termMonths): float
    {
        if ($this->interest_type === 'flat_rate') {
            $totalInterest = $principal * ($this->interest_rate / 100) * ($termMonths / 12);
            return ($principal + $totalInterest) / $termMonths;
        }

        if ($this->interest_type === 'fixed') {
            // Simple fixed interest calculation
            $monthlyRate = ($this->interest_rate / 100) / 12;
            $totalInterest = $principal * $monthlyRate * $termMonths;
            return ($principal + $totalInterest) / $termMonths;
        }

        // Reducing balance (amortizing loan)
        $monthlyRate = ($this->interest_rate / 100) / 12;
        if ($monthlyRate == 0) {
            return $principal / $termMonths;
        }
        
        return $principal * $monthlyRate * pow(1 + $monthlyRate, $termMonths) / (pow(1 + $monthlyRate, $termMonths) - 1);
    }

    /**
     * Calculate total interest.
     */
    public function calculateTotalInterest(float $principal, int $termMonths): float
    {
        $monthlyPayment = $this->calculateMonthlyPayment($principal, $termMonths);
        return ($monthlyPayment * $termMonths) - $principal;
    }

    /**
     * Calculate processing fee.
     */
    public function calculateProcessingFee(float $amount): float
    {
        $fee = $this->processing_fee;
        
        if ($this->processing_fee_percentage > 0) {
            $fee += $amount * ($this->processing_fee_percentage / 100);
        }
        
        return $fee;
    }

    /**
     * Check if amount is within range.
     */
    public function isAmountValid(float $amount): bool
    {
        return $amount >= $this->min_amount && $amount <= $this->max_amount;
    }

    /**
     * Check if term is within range.
     */
    public function isTermValid(int $months): bool
    {
        return $months >= $this->min_term_months && $months <= $this->max_term_months;
    }

    /**
     * Get the route key for the model.
     */
    public function getRouteKeyName(): string
    {
        return 'slug';
    }

    /**
     * Boot the model.
     */
    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            if (empty($model->slug)) {
                $model->slug = Str::slug($model->name);
            }
        });
    }
}
