<?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 LoanApplication extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'reference_number',
        'member_id',
        'loan_product_id',
        'user_id',
        'amount_requested',
        'amount_approved',
        'amount_disbursed',
        'currency',
        'term_months',
        'interest_rate',
        'purpose',
        'total_interest',
        'total_repayable',
        'monthly_payment',
        'processing_fee',
        'status',
        'manager_id',
        'manager_reviewed_at',
        'manager_review_notes',
        'manager_approved',
        'super_manager_id',
        'super_manager_approved_at',
        'super_manager_notes',
        'super_manager_approved',
        'rejection_reason',
        'rejected_at',
        'disbursed_at',
        'disbursed_by',
        'disbursement_reference',
        'disbursement_method',
        'amount_repaid',
        'principal_repaid',
        'interest_repaid',
        'outstanding_balance',
        'next_payment_date',
        'next_payment_amount',
        'guarantors',
        'collateral',
        'employment_status',
        'employer_name',
        'monthly_income',
        'income_currency',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'amount_requested' => 'decimal:2',
        'amount_approved' => 'decimal:2',
        'amount_disbursed' => 'decimal:2',
        'interest_rate' => 'decimal:2',
        'total_interest' => 'decimal:2',
        'total_repayable' => 'decimal:2',
        'monthly_payment' => 'decimal:2',
        'processing_fee' => 'decimal:2',
        'amount_repaid' => 'decimal:2',
        'principal_repaid' => 'decimal:2',
        'interest_repaid' => 'decimal:2',
        'outstanding_balance' => 'decimal:2',
        'next_payment_amount' => 'decimal:2',
        'monthly_income' => 'decimal:2',
        'term_months' => 'integer',
        'manager_approved' => 'boolean',
        'super_manager_approved' => 'boolean',
        'guarantors' => 'array',
        'collateral' => 'array',
        'manager_reviewed_at' => 'datetime',
        'super_manager_approved_at' => 'datetime',
        'rejected_at' => 'datetime',
        'disbursed_at' => 'datetime',
        'next_payment_date' => 'date',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

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

    /**
     * Get the member for the loan application.
     */
    public function member(): BelongsTo
    {
        return $this->belongsTo(Member::class);
    }

    /**
     * Get the loan product for the application.
     */
    public function loanProduct(): BelongsTo
    {
        return $this->belongsTo(LoanProduct::class);
    }

    /**
     * Get the user for the application.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Get the manager who reviewed the application.
     */
    public function manager(): BelongsTo
    {
        return $this->belongsTo(User::class, 'manager_id');
    }

    /**
     * Get the super manager who approved the application.
     */
    public function superManager(): BelongsTo
    {
        return $this->belongsTo(User::class, 'super_manager_id');
    }

    /**
     * Get the user who disbursed the loan.
     */
    public function disburser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'disbursed_by');
    }

    /**
     * Get the documents for the loan application.
     */
    public function documents(): HasMany
    {
        return $this->hasMany(LoanDocument::class);
    }

    /**
     * Get the repayments for the loan application.
     */
    public function repayments(): HasMany
    {
        return $this->hasMany(LoanRepayment::class);
    }

    /**
     * Get the amortization schedule for the loan.
     */
    public function amortizationSchedule(): HasMany
    {
        return $this->hasMany(LoanAmortizationSchedule::class);
    }

    /**
     * Get the status badge color.
     */
    public function getStatusBadgeColorAttribute(): string
    {
        return match($this->status) {
            'draft' => 'gray',
            'pending' => 'yellow',
            'under_review' => 'blue',
            'manager_approved' => 'indigo',
            'approved' => 'green',
            'rejected' => 'red',
            'disbursed' => 'purple',
            'active' => 'teal',
            'completed' => 'green',
            'defaulted' => 'red',
            'cancelled' => 'gray',
            default => 'gray',
        };
    }

    /**
     * Get the applicant name.
     */
    public function getApplicantNameAttribute(): string
    {
        return $this->member?->full_name ?? $this->user?->name ?? 'N/A';
    }

    /**
     * Get remaining balance (alias for outstanding_balance).
     */
    public function getRemainingBalanceAttribute(): float
    {
        return (float) ($this->outstanding_balance ?? ($this->total_repayable - $this->amount_repaid));
    }

    /**
     * Scope a query to only include pending applications.
     */
    public function scopePending($query)
    {
        return $query->where('status', 'pending');
    }

    /**
     * Scope a query to only include approved applications.
     */
    public function scopeApproved($query)
    {
        return $query->whereIn('status', ['approved', 'disbursed', 'active']);
    }

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

    /**
     * Scope a query to only include overdue loans.
     */
    public function scopeOverdue($query)
    {
        return $query->where('status', 'active')
            ->where('next_payment_date', '<', now());
    }

    /**
     * Generate a unique reference number.
     */
    public static function generateReferenceNumber(): string
    {
        do {
            $reference = 'LOAN-' . date('Ymd') . '-' . strtoupper(Str::random(6));
        } while (self::where('reference_number', $reference)->exists());

        return $reference;
    }

    /**
     * Check if application is pending.
     */
    public function isPending(): bool
    {
        return in_array($this->status, ['pending', 'under_review']);
    }

    /**
     * Check if application is approved.
     */
    public function isApproved(): bool
    {
        return $this->status === 'approved';
    }

    /**
     * Check if loan is active.
     */
    public function isActive(): bool
    {
        return $this->status === 'active';
    }

    /**
     * Check if application can be approved by manager.
     */
    public function canBeApprovedByManager(): bool
    {
        return in_array($this->status, ['pending', 'under_review']);
    }

    /**
     * Check if application can be approved by super manager.
     */
    public function canBeApprovedBySuperManager(): bool
    {
        return $this->status === 'manager_approved' && $this->manager_approved;
    }

    /**
     * Check if loan can be disbursed.
     */
    public function canBeDisbursed(): bool
    {
        return $this->status === 'approved' && $this->super_manager_approved;
    }

    /**
     * Calculate outstanding balance.
     */
    public function calculateOutstandingBalance(): float
    {
        return $this->total_repayable - $this->amount_repaid;
    }

    /**
     * Get repayment progress percentage.
     */
    public function getRepaymentProgress(): float
    {
        if ($this->total_repayable <= 0) {
            return 0;
        }

        return ($this->amount_repaid / $this->total_repayable) * 100;
    }
}
