<?php

declare(strict_types=1);

namespace Tests\Unit;

use App\DTOs\ExtendCreditData;
use App\Models\Client;
use App\Models\Company;
use App\Models\Credit;
use App\Models\Installment;
use App\Models\User;
use App\Services\Credits\CreditOperationOrchestrator;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;

/**
 * #90 — La EXTENSIÓN SIMPLE (más plazo, sin dinero nuevo) debe redistribuir el
 * saldo pendiente TAL CUAL, sin recargar interés sobre él (el saldo ya incluye
 * el interés del crédito original → recargar sería interés-sobre-interés).
 *
 * Antes: el crédito hijo heredaba la tasa original → total = saldo × (1+tasa).
 * Ahora: tasa 0 → total = saldo. Para cobrar interés por la prórroga existe la
 * operación aparte "extender con interés".
 */
class ExtendCreditOperationTest extends TestCase
{
    use DatabaseTransactions;

    private Company $company;

    private User $user;

    protected function setUp(): void
    {
        parent::setUp();

        $this->company = Company::factory()->create(['interest_method' => 'flat_rate']);
        $this->user = User::factory()->create(['company_id' => $this->company->id]);
        $this->actingAs($this->user);
    }

    /** Crédito activo SIN pagos (la extensión simple exige que no haya capital pagado). */
    private function createCreditWithoutPayments(float $amount, float $interestRate, int $installments): Credit
    {
        $total = $amount * (1 + $interestRate / 100);
        $perInstallment = $total / $installments;

        $client = Client::factory()->create(['company_id' => $this->company->id]);

        $credit = Credit::create([
            'company_id' => $this->company->id,
            'client_id' => $client->id,
            'collector_user_id' => $this->user->id,
            'created_by_user_id' => $this->user->id,
            'status' => Credit::STATUS_DELAYED,
            'amount' => $amount,
            'interest_rate' => $interestRate,
            'installments_count' => $installments,
            'periodicity' => 'weekly',
            'start_date' => Carbon::now()->subWeeks($installments),
        ]);

        for ($i = 1; $i <= $installments; $i++) {
            Installment::create([
                'company_id' => $this->company->id,
                'credit_id' => $credit->id,
                'installment_number' => $i,
                'status' => Installment::STATUS_PENDING,
                'due_date' => Carbon::now()->subWeeks($installments - $i),
                'principal_amount' => $amount / $installments,
                'interest_amount' => ($amount * $interestRate / 100) / $installments,
                'total_amount' => $perInstallment,
                'principal_balance_after' => $perInstallment,
                'amount_paid' => 0,
            ]);
        }

        return $credit->fresh(['installments']);
    }

    #[Test]
    public function plain_extension_redistributes_balance_without_charging_interest(): void
    {
        // 500.000 al 20% → total 600.000, 10 cuotas, sin pagos. Saldo pendiente = 600.000.
        $credit = $this->createCreditWithoutPayments(amount: 500000, interestRate: 20, installments: 10);

        $dto = new ExtendCreditData(
            creditId: $credit->id,
            newInstallmentsCount: 12,
            periodicity: 'weekly',
            startDate: Carbon::today(),
            reason: 'Más plazo, sin dinero nuevo',
        );

        $result = app(CreditOperationOrchestrator::class)->extend($dto);
        $newCredit = $result->newCredit->fresh(['installments']);

        // El hijo NO recarga interés: tasa 0 y total = saldo (600k), NO 600k×1.20 = 720k.
        $this->assertEquals(0.0, (float) $newCredit->interest_rate, 'El crédito hijo de una extensión simple debe tener tasa 0');
        $this->assertEqualsWithDelta(600000, (float) $newCredit->amount, 0.01);
        $this->assertEqualsWithDelta(
            600000,
            (float) $newCredit->installments->sum('total_amount'),
            0.01,
            'La extensión simple debe redistribuir el saldo SIN interés nuevo (antes del fix daba 720.000)',
        );
        $this->assertSame(12, $newCredit->installments->count());

        // El crédito original queda 'extended'.
        $this->assertSame(Credit::STATUS_EXTENDED, $credit->fresh()->status);
    }
}
