<?php

namespace App\Models;

use App\Traits\MultiTenantScope;
use App\ValueObjects\Money;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Installment extends Model
{
    use HasFactory, MultiTenantScope;

    public const STATUS_PENDING = 'pending';

    public const STATUS_PARTIAL_PAID = 'partial_paid';

    public const STATUS_PAID = 'paid';

    public const STATUS_OVERDUE = 'overdue';

    protected $fillable = [
        'company_id',
        'credit_id',
        'installment_number',
        'status',
        'due_date',
        'paid_date',
        'principal_amount',
        'interest_amount',
        'total_amount',
        'principal_balance_after',
        'amount_paid',
        'forgiven_amount',
    ];

    protected $casts = [
        'due_date' => 'date',
        'paid_date' => 'date',
        'principal_amount' => 'decimal:2',
        'interest_amount' => 'decimal:2',
        'total_amount' => 'decimal:2',
        'principal_balance_after' => 'decimal:2',
        'amount_paid' => 'decimal:2',
        'forgiven_amount' => 'decimal:2',
    ];

    /*=========================================================
    | RELACIONES
    =========================================================*/
    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

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

    public function paymentsApplied()
    {
        return $this->belongsToMany(Payment::class, 'payment_installment')
            ->withPivot('applied_amount')
            ->withTimestamps();
    }

    /*=========================================================
    | LABELS / COLORES PARA UI
    =========================================================*/
    public function getStatusLabel(): string
    {
        // Cuota paid con forgiven_amount registrado → mostrar etiqueta diferenciada
        if ($this->status === self::STATUS_PAID && $this->forgiven_amount > 0) {
            return 'Condonada';
        }

        return match ($this->status) {
            self::STATUS_PAID => 'Pagada',
            self::STATUS_PARTIAL_PAID => 'Pago Parcial',
            self::STATUS_OVERDUE => 'Vencida',
            self::STATUS_PENDING => 'Pendiente',
            default => ucfirst($this->status),
        };
    }

    public function getStatusBadgeColor(): string
    {
        if ($this->status === self::STATUS_PAID && $this->forgiven_amount > 0) {
            return 'purple';
        }

        return match ($this->status) {
            self::STATUS_PAID => 'success',
            self::STATUS_PARTIAL_PAID => 'info',
            self::STATUS_OVERDUE => 'danger',
            default => 'gray',
        };
    }

    public function isCondoned(): bool
    {
        return $this->status === self::STATUS_PAID
            && $this->forgiven_amount !== null
            && (float) $this->forgiven_amount > 0;
    }

    /*=========================================================
    | ACCESSORS
    =========================================================*/

    /**
     * Monto pendiente total de esta cuota (principal + interés no pagados).
     */
    public function getRemainingAmountAttribute(): float
    {
        return Money::of($this->total_amount)->subtract($this->amount_paid)->max(0)->value();
    }

    /**
     * Principal efectivamente pagado en esta cuota.
     *
     * Cuota pagada completa → devuelve principal_amount íntegro.
     * Cuota con pago parcial → prorrateo proporcional:
     *   principal_paid = amount_paid × (principal_amount / total_amount)
     *
     * Fuente única de verdad para el desglose de pagos.
     * Movido desde CreditController (lógica financiera no pertenece al controlador).
     */
    public function getPrincipalPaidAttribute(): float
    {
        if ($this->status === self::STATUS_PAID) {
            return (float) $this->principal_amount;
        }

        $totalAmount = (float) $this->total_amount;
        if ($totalAmount <= 0.0) {
            return 0.0;
        }

        return (float) $this->amount_paid * ((float) $this->principal_amount / $totalAmount);
    }

    /**
     * Interés efectivamente pagado en esta cuota.
     *
     * Cuota pagada completa → devuelve interest_amount íntegro.
     * Cuota con pago parcial → prorrateo proporcional:
     *   interest_paid = amount_paid × (interest_amount / total_amount)
     */
    public function getInterestPaidAttribute(): float
    {
        if ($this->status === self::STATUS_PAID) {
            return (float) $this->interest_amount;
        }

        $totalAmount = (float) $this->total_amount;
        if ($totalAmount <= 0.0) {
            return 0.0;
        }

        return (float) $this->amount_paid * ((float) $this->interest_amount / $totalAmount);
    }

    /**
     * Principal pendiente de pago de esta cuota.
     * Usa Money para precisión exacta con bcmath.
     */
    public function getPrincipalPendingAttribute(): float
    {
        return Money::of($this->principal_amount)->subtract($this->principal_paid)->max(0)->value();
    }

    /**
     * Interés pendiente de pago de esta cuota.
     * Usa Money para precisión exacta con bcmath.
     */
    public function getInterestPendingAttribute(): float
    {
        return Money::of($this->interest_amount)->subtract($this->interest_paid)->max(0)->value();
    }
}
