<?php

namespace App\Models;

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

class Loan extends Model
{
    use HasFactory;

    protected $fillable = [
        'uuid',
        'loan_no',
        'customer_id',
        'product_id',
        'branch_id',
        'account_id',
        'principal',
        'interest_rate',
        'interest_method',
        'tenor_months',
        'processing_fee',
        'disbursed_amount',
        'outstanding_principal',
        'outstanding_interest',
        'total_repayable',
        'total_paid',
        'purpose',
        'application_date',
        'approval_date',
        'disbursement_date',
        'maturity_date',
        'next_due_date',
        'status',
        'credit_score',
        'officer_id',
        'approved_by',
        'disbursed_by',
        'rejection_reason',
        'created_by',
    ];

    protected static function boot(): void
    {
        parent::boot();

        static::creating(function (self $loan): void {
            if (empty($loan->uuid)) {
                $loan->uuid = (string) Str::uuid();
            }
        });
    }

    protected function casts(): array
    {
        return [
            'principal' => 'decimal:2',
            'interest_rate' => 'decimal:4',
            'processing_fee' => 'decimal:2',
            'disbursed_amount' => 'decimal:2',
            'outstanding_principal' => 'decimal:2',
            'outstanding_interest' => 'decimal:2',
            'total_repayable' => 'decimal:2',
            'total_paid' => 'decimal:2',
            'application_date' => 'date',
            'approval_date' => 'date',
            'disbursement_date' => 'date',
            'maturity_date' => 'date',
            'next_due_date' => 'date',
        ];
    }

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

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

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

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

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

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

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

    /** Lifecycle milestones for timeline UI. */
    public function timelineSteps(): array
    {
        $status = strtolower((string) $this->status);
        $steps = [
            [
                'key' => 'application',
                'label' => 'Application',
                'date' => $this->application_date,
                'done' => true,
            ],
            [
                'key' => 'underwriting',
                'label' => 'Underwriting',
                'date' => $this->application_date,
                'done' => in_array($status, ['underwriting', 'approved', 'disbursed', 'active', 'in_arrears', 'closed', 'completed', 'written_off'], true)
                    || ($this->approval_date !== null),
            ],
            [
                'key' => 'approval',
                'label' => 'Approved',
                'date' => $this->approval_date,
                'done' => $this->approval_date !== null
                    || in_array($status, ['approved', 'disbursed', 'active', 'in_arrears', 'closed', 'completed'], true),
            ],
            [
                'key' => 'disbursement',
                'label' => 'Disbursed',
                'date' => $this->disbursement_date,
                'done' => $this->disbursement_date !== null
                    || in_array($status, ['disbursed', 'active', 'in_arrears', 'closed', 'completed'], true),
            ],
            [
                'key' => 'maturity',
                'label' => 'Maturity',
                'date' => $this->maturity_date,
                'done' => in_array($status, ['closed', 'completed'], true),
            ],
        ];

        if ($status === 'rejected') {
            $steps[] = [
                'key' => 'rejected',
                'label' => 'Rejected',
                'date' => $this->updated_at,
                'done' => true,
                'danger' => true,
            ];
        }

        return $steps;
    }

    /** Progress through tenor (0–100). */
    public function durationProgressPercent(): float
    {
        $start = $this->disbursement_date ?? $this->approval_date ?? $this->application_date;
        $end = $this->maturity_date;
        if (! $start || ! $end || $end->lte($start)) {
            if ($this->tenor_months > 0 && $start) {
                $end = $start->copy()->addMonths((int) $this->tenor_months);
            } else {
                return 0.0;
            }
        }
        $total = max(1, $start->diffInDays($end));
        $elapsed = max(0, $start->diffInDays(now()));
        return min(100, round(($elapsed / $total) * 100, 1));
    }

    public function daysRemaining(): ?int
    {
        if (! $this->maturity_date) {
            return null;
        }
        return (int) now()->copy()->startOfDay()->diffInDays($this->maturity_date->copy()->startOfDay(), false);
    }

    /** Interest accrued / scheduled so far for customer & staff glance. */
    public function interestSummary(): array
    {
        $schedules = $this->relationLoaded('schedules') ? $this->schedules : $this->schedules()->get();
        $repayments = $this->relationLoaded('repayments') ? $this->repayments : $this->repayments()->get();

        $scheduledInterest = (float) $schedules->sum('interest_due');
        $interestPaid = (float) $repayments->sum(fn ($r) => (float) ($r->interest_portion ?? 0));
        $outstandingInterest = (float) ($this->outstanding_interest ?? max(0, $scheduledInterest - $interestPaid));

        // Accrued estimate: portion of scheduled interest by elapsed tenor
        $progress = $this->durationProgressPercent() / 100;
        $accruedEstimate = round($scheduledInterest * $progress, 2);
        if ($accruedEstimate < $interestPaid) {
            $accruedEstimate = $interestPaid;
        }

        return [
            'rate' => (float) $this->interest_rate,
            'method' => (string) $this->interest_method,
            'scheduled_total' => $scheduledInterest,
            'paid' => $interestPaid,
            'outstanding' => $outstandingInterest,
            'accrued_estimate' => $accruedEstimate,
            'principal_outstanding' => (float) $this->outstanding_principal,
            'total_paid' => (float) ($this->total_paid ?? $repayments->sum('amount')),
        ];
    }

}
