<?php

declare(strict_types=1);

namespace App\Services\Credits\Operations;

use App\DTOs\CreditOperationResult;
use App\DTOs\ExtendCreditData;
use App\Enums\CreditAuditEvent;
use App\Models\Credit;
use App\Models\CreditRestructureLog;
use App\ValueObjects\Money;

/**
 * Operación de EXTENSIÓN de crédito.
 *
 * DEFINICIÓN:
 * Ampliación del PLAZO de pago sin entregar dinero nuevo.
 * El saldo pendiente se redistribuye en más cuotas.
 *
 * ECUACIÓN FINANCIERA:
 *   nuevo_principal = saldo_pendiente_original
 *   cash_out = 0 (no hay desembolso)
 *   compensated_amount = saldo_pendiente
 *
 * ESTADOS:
 *   Entrada: active, delayed, overdue
 *   Salida original: extended
 *   Salida nuevo: active
 */
class ExtendCreditOperation extends BaseCreditOperation
{
    /**
     * Ejecuta la extensión del crédito.
     *
     * PRECONDICIÓN: Validación ya realizada por CreditOperationValidator
     *
     * @param  Credit  $credit  Crédito a extender (locked for update)
     * @param  ExtendCreditData  $data  Datos de la extensión
     * @param  Money  $remainingBalance  Saldo pendiente calculado
     */
    public function execute(
        Credit $credit,
        ExtendCreditData $data,
        Money $remainingBalance,
    ): CreditOperationResult {
        // 1. Crear nuevo crédito hijo con saldo pendiente
        $newCredit = $this->createChildCredit(
            originalCredit: $credit,
            principal: $remainingBalance,
            installmentsCount: $data->newInstallmentsCount,
            periodicity: $data->periodicity,
            startDate: $data->startDate,
            firstDueDateOverride: $data->firstDueDateOverride,
            dueDay1: $data->dueDay1,
            dueDay2: $data->dueDay2,
            // #90 — Extensión simple = SOLO más plazo, "sin dinero nuevo": el saldo
            // pendiente (que ya incluye el interés del crédito original) se redistribuye
            // tal cual, con tasa 0, para NO recargar interés sobre interés (anatocismo).
            // Para cobrar interés por la prórroga existe ExtendWithInterestOperation.
            interestRate: '0',
        );

        // 2. Cerrar crédito original con estado 'extended'
        $this->closeOriginalCredit($credit, Credit::STATUS_EXTENDED);

        // 3. Registrar en credit_restructure_logs
        $restructureLog = $this->logRestructure(
            originalCredit: $credit,
            newCredit: $newCredit,
            type: CreditRestructureLog::TYPE_EXTENSION,
            previousBalance: $remainingBalance,
            newPrincipal: $remainingBalance,
            additionalCapital: Money::zero(),
            capitalizedInterest: Money::zero(),
            newInterestRate: '0', // #90 — el hijo redistribuye el saldo sin interés nuevo
            newInstallmentCount: $data->newInstallmentsCount,
            newPeriodicity: $data->periodicity,
            reason: $data->reason,
            metadata: [
                'operation' => 'extension',
                'input_data' => $data->toArray(),
            ],
        );

        // 4. Registrar operación financiera (sin movimiento de caja)
        $financialOperation = $this->logFinancialOperation(
            originalCredit: $credit,
            newCredit: $newCredit,
            operationType: 'credit_extension',
            creditAmount: $remainingBalance,
            compensatedAmount: $remainingBalance,
            cashOut: Money::zero(),
            expenseId: null, // No hay desembolso
            notes: 'Extensión de crédito - Sin movimiento de caja',
        );

        // 5. Registrar auditoría
        $this->logAudit(
            creditId: $credit->id,
            action: CreditAuditEvent::CREDIT_EXTENDED,
            data: array_merge($data->toArray(), [
                'previous_balance' => $remainingBalance->value(),
                'new_credit_id' => $newCredit->id,
            ]),
            newCreditId: $newCredit->id,
        );

        // 6. Construir y retornar resultado
        return $this->buildResult(
            originalCredit: $credit,
            newCredit: $newCredit,
            restructureLog: $restructureLog,
            financialOperation: $financialOperation,
            previousBalance: $remainingBalance,
            newPrincipal: $remainingBalance,
            cashOut: Money::zero(),
            compensatedAmount: $remainingBalance,
            operationType: 'extension',
        );
    }
}
