<?php

namespace App\Models;

use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Loan extends Model
{
    use BelongsToTenant;

    public const AUTO_DEBIT_AUTOMATIC = 'automatic';
    public const AUTO_DEBIT_MANUAL_ON_DEFAULT = 'manual_with_default_auto_debit';
    public const AUTO_DEBIT_MANUAL_ONLY = 'manual_only';

    protected $fillable = [
        'tenant_id',
        'branch_id',
        'customer_id',
        'loan_product_id',
        'created_by',
        'loan_number',
        'principal',
        'interest_rate',
        'interest_method',
        'interest_amount',
        'processing_fee',
        'processing_fee_timing',
        'auto_debit_mode',
        'auto_debit_savings_account_id',
        'auto_debit_authorized_at',
        'auto_debit_last_attempt_at',
        'auto_debit_failure_reason',
        'total_payable',
        'amount_disbursed',
        'balance',
        'repayment_frequency',
        'term_days',
        'term_value',
        'term_unit',
        'status',
        'purpose',
        'collateral',
        'application_date',
        'first_repayment_date',
        'approved_at',
        'approved_by',
        'disbursed_at',
        'disbursed_by',
        'due_date',
        'rejected_reason',
    ];

    protected function casts(): array
    {
        return [
            'principal' => 'decimal:2',
            'interest_rate' => 'decimal:2',
            'interest_amount' => 'decimal:2',
            'processing_fee' => 'decimal:2',
            'total_payable' => 'decimal:2',
            'amount_disbursed' => 'decimal:2',
            'balance' => 'decimal:2',
            'term_value' => 'integer',
            'auto_debit_authorized_at' => 'datetime',
            'auto_debit_last_attempt_at' => 'datetime',
            'application_date' => 'date',
            'first_repayment_date' => 'date',
            'approved_at' => 'datetime',
            'disbursed_at' => 'datetime',
            'due_date' => 'date',
        ];
    }

    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class);
    }

    public function product(): BelongsTo
    {
        return $this->belongsTo(LoanProduct::class, 'loan_product_id');
    }

    public function branch(): BelongsTo
    {
        return $this->belongsTo(Branch::class);
    }

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    public function approver(): BelongsTo
    {
        return $this->belongsTo(User::class, 'approved_by');
    }

    public function disburser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'disbursed_by');
    }

    public function autoDebitAccount(): BelongsTo
    {
        return $this->belongsTo(SavingsAccount::class, 'auto_debit_savings_account_id');
    }

    public function guarantors(): HasMany
    {
        return $this->hasMany(LoanGuarantor::class);
    }

    public function schedules(): HasMany
    {
        return $this->hasMany(LoanRepaymentSchedule::class);
    }

    public function allSchedules(): HasMany
    {
        return $this->hasMany(LoanRepaymentSchedule::class)->withoutGlobalScope('current_schedule');
    }

    public function archivedSchedules(): HasMany
    {
        return $this->hasMany(LoanRepaymentSchedule::class)
            ->withoutGlobalScope('current_schedule')
            ->where('is_current', false)
            ->orderByDesc('schedule_version')
            ->orderBy('installment_no');
    }

    public function payments(): HasMany
    {
        return $this->hasMany(LoanPayment::class);
    }

    public function processingFeeTimingLabel(): string
    {
        return LoanProduct::PROCESSING_FEE_TIMINGS[$this->processing_fee_timing] ?? str($this->processing_fee_timing ?? 'before_disbursement')->headline()->toString();
    }

    public static function autoDebitModes(): array
    {
        return [
            self::AUTO_DEBIT_AUTOMATIC => 'Automatic debit',
            self::AUTO_DEBIT_MANUAL_ON_DEFAULT => 'Manual, auto debit if defaulted',
            self::AUTO_DEBIT_MANUAL_ONLY => 'Manual only',
        ];
    }

    public function autoDebitModeLabel(): string
    {
        return self::autoDebitModes()[$this->auto_debit_mode] ?? self::autoDebitModes()[self::AUTO_DEBIT_MANUAL_ONLY];
    }

    public function netDisbursementAmount(): float
    {
        $principal = (float) $this->principal;
        $fee = (float) $this->processing_fee;

        if (($this->processing_fee_timing ?? 'before_disbursement') !== 'deduct_from_disbursement') {
            return $principal;
        }

        return round(max(0, $principal - $fee), 2);
    }
}
