<?php

namespace App\Support\Concerns;

use App\Enums\Periodicity;
use App\Support\MoneyCalculator;
use App\ValueObjects\Money;
use Exception;

/**
 * Utilidades matemáticas para cálculos resumidos de créditos.
 *
 * IMPORTANTE:
 * - Este trait NO genera cuotas reales ni maneja fechas.
 * - Solo produce resúmenes numéricos rápidos para el formulario (UX).
 *
 * Usa Money Value Object con BC Math para precisión financiera exacta.
 */
trait CalculatesCreditSummary
{
    /**
     * Cálculo resumido #1:
     * Interés Fijo Simple (Tasa Total del plazo completo).
     */
    protected static function calculateFlatRateSummary(
        float $amount,
        float $rate,
        int $installments,
        ?string $periodicity = null
    ): array {
        if ($amount <= 0 || $rate < 0 || $installments < 1) {
            return [
                'payment' => null,
                'totalRepay' => null,
                'totalInterest' => null,
            ];
        }

        $principal = Money::of($amount);
        $totalInterest = $principal->percentage((string) $rate);
        $totalRepay = $principal->add($totalInterest);
        $estimatedPayment = $totalRepay->divide($installments);

        return [
            'payment' => $estimatedPayment->value(),
            'totalRepay' => $totalRepay->value(),
            'totalInterest' => $totalInterest->value(),
        ];
    }

    /**
     * Cálculo resumido #2:
     * Interés Fijo con Tasa Mensual Proyectada.
     *
     * La tasa ingresada es mensual y se proyecta según la periodicidad.
     */
    protected static function calculateFlatRateProjectedSummary(
        float $amount,
        float $rate,
        int $installments,
        ?string $periodicity
    ): array {
        if ($amount <= 0 || $rate < 0 || $installments < 1 || ! $periodicity) {
            return [
                'payment' => null,
                'totalRepay' => null,
                'totalInterest' => null,
            ];
        }

        if (! in_array($periodicity, array_column(Periodicity::cases(), 'value'), true)) {
            throw new Exception("Periodicidad '{$periodicity}' no reconocida.");
        }

        // Factor de término según periodicidad
        $termFactor = match ($periodicity) {
            Periodicity::DAILY->value => bcdiv((string) $installments, '30', 8),
            Periodicity::WEEKLY->value => bcdiv((string) $installments, '4', 8),
            Periodicity::BIWEEKLY->value => bcdiv((string) $installments, '2', 8),
            Periodicity::MONTHLY->value => (string) $installments,
            default => throw new Exception("Periodicidad '{$periodicity}' no soportada."),
        };

        $principal = Money::of($amount);
        $rateDecimal = MoneyCalculator::percentToDecimal((string) $rate);

        // Interés total = Principal × Tasa × Factor de término
        $totalInterest = $principal->multiply($rateDecimal)->multiply($termFactor);
        $totalRepay = $principal->add($totalInterest);
        $estimatedPayment = $totalRepay->divide($installments);

        return [
            'payment' => $estimatedPayment->value(),
            'totalRepay' => $totalRepay->value(),
            'totalInterest' => $totalInterest->value(),
        ];
    }

    /**
     * Cálculo resumido #3:
     * Método de Amortización sobre Saldo Decreciente (Diminishing Balance).
     *
     * La tasa es mensual y se aplica el método francés (cuota fija).
     */
    protected static function calculateDiminishingBalanceSummary(
        float $amount,
        float $monthlyRatePercent,
        int $installments,
        ?string $periodicity
    ): array {
        if ($amount <= 0 || $monthlyRatePercent < 0 || $installments < 1) {
            return [
                'payment' => null,
                'totalRepay' => null,
                'totalInterest' => null,
            ];
        }

        $principal = Money::of($amount);
        $rateDecimal = MoneyCalculator::percentToDecimal((string) $monthlyRatePercent);

        // Cuota fija método francés
        $payment = MoneyCalculator::frenchMethodPayment($principal, $rateDecimal, $installments);

        $totalRepay = $payment->multiply($installments);
        $totalInterest = $totalRepay->subtract($principal);

        return [
            'payment' => $payment->value(),
            'totalRepay' => $totalRepay->value(),
            'totalInterest' => $totalInterest->value(),
        ];
    }
}
