<?php

declare(strict_types=1);

namespace App\DTOs;

use Carbon\Carbon;
use InvalidArgumentException;

/**
 * Representa una cuota individual en un plan de pagos personalizado.
 *
 * Permite definir cuotas con montos irregulares (no calculados automáticamente).
 * Usado principalmente en reestructuraciones donde el usuario define
 * montos específicos por cuota.
 */
readonly class CustomInstallmentData
{
    public Carbon $dueDate;

    public function __construct(
        public int $number,             // Número de cuota (1, 2, 3...)
        public float $totalAmount,      // Monto total de la cuota
        Carbon|string $dueDate,         // Fecha de vencimiento
        public ?float $principalAmount = null, // Opcional: principal específico
        public ?float $interestAmount = null,  // Opcional: interés específico
    ) {
        if ($number < 1) {
            throw new InvalidArgumentException('El número de cuota debe ser mayor a 0.');
        }

        if ($totalAmount <= 0) {
            throw new InvalidArgumentException(
                "El monto de la cuota #{$number} debe ser mayor a 0."
            );
        }

        $this->dueDate = $dueDate instanceof Carbon
            ? $dueDate
            : Carbon::parse($dueDate);

        // Validar coherencia si ambos valores son proporcionados
        if ($principalAmount !== null && $interestAmount !== null) {
            $sum = round($principalAmount + $interestAmount, 2);
            $total = round($totalAmount, 2);

            if (abs($sum - $total) > 0.01) {
                throw new InvalidArgumentException(sprintf(
                    'Cuota #%d: principal (%s) + interés (%s) = %s, pero total es %s',
                    $number,
                    number_format($principalAmount, 2),
                    number_format($interestAmount, 2),
                    number_format($sum, 2),
                    number_format($total, 2)
                ));
            }
        }
    }

    /**
     * Crea instancia desde array (útil para formularios).
     */
    public static function fromArray(array $data): self
    {
        return new self(
            number: (int) $data['number'],
            totalAmount: (float) $data['total_amount'],
            dueDate: $data['due_date'],
            principalAmount: isset($data['principal_amount']) ? (float) $data['principal_amount'] : null,
            interestAmount: isset($data['interest_amount']) ? (float) $data['interest_amount'] : null,
        );
    }

    /**
     * Convierte a array para persistencia/serialización.
     */
    public function toArray(): array
    {
        return [
            'number' => $this->number,
            'total_amount' => $this->totalAmount,
            'due_date' => $this->dueDate->toDateString(),
            'principal_amount' => $this->principalAmount,
            'interest_amount' => $this->interestAmount,
        ];
    }
}
