<?php

namespace Tests\Unit;

use App\Services\Audit\AuditPresenter;
use PHPUnit\Framework\TestCase;

class AuditPresenterTest extends TestCase
{
    // =========================================================================
    // translateFieldKey
    // =========================================================================

    public function test_translate_known_keys(): void
    {
        $this->assertSame('Monto', AuditPresenter::translateFieldKey('amount'));
        $this->assertSame('Tasa de interés', AuditPresenter::translateFieldKey('interest_rate'));
        $this->assertSame('Periodicidad', AuditPresenter::translateFieldKey('periodicity'));
        $this->assertSame('Estado', AuditPresenter::translateFieldKey('status'));
        $this->assertSame('Fecha de pago', AuditPresenter::translateFieldKey('payment_date'));
        $this->assertSame('Total pagado', AuditPresenter::translateFieldKey('total_paid'));
        $this->assertSame('Saldo pendiente', AuditPresenter::translateFieldKey('balance'));
        $this->assertSame('Número de cuotas', AuditPresenter::translateFieldKey('installments'));
        $this->assertSame('Número de cuotas', AuditPresenter::translateFieldKey('new_installments'));
        $this->assertSame('Capital adicional', AuditPresenter::translateFieldKey('additional_capital'));
        $this->assertSame('Crédito generado', AuditPresenter::translateFieldKey('new_credit_id'));
        $this->assertSame('Crédito origen', AuditPresenter::translateFieldKey('from_credit_id'));
        $this->assertSame('Motivo', AuditPresenter::translateFieldKey('reason'));
        $this->assertSame('Fecha de ejecución', AuditPresenter::translateFieldKey('executed_at'));
    }

    public function test_translate_unknown_key_uses_fallback(): void
    {
        $this->assertSame('Custom field name', AuditPresenter::translateFieldKey('custom_field_name'));
    }

    // =========================================================================
    // translateFieldValue
    // =========================================================================

    public function test_translate_null_value(): void
    {
        $this->assertSame('—', AuditPresenter::translateFieldValue('amount', null));
    }

    public function test_translate_boolean_values(): void
    {
        $this->assertSame('Sí', AuditPresenter::translateFieldValue('some_field', true));
        $this->assertSame('No', AuditPresenter::translateFieldValue('some_field', false));
    }

    public function test_translate_status_values(): void
    {
        $this->assertSame('Activo', AuditPresenter::translateFieldValue('status', 'active'));
        $this->assertSame('Pagado', AuditPresenter::translateFieldValue('status', 'paid'));
        $this->assertSame('Vencido', AuditPresenter::translateFieldValue('status', 'overdue'));
        $this->assertSame('Cancelado', AuditPresenter::translateFieldValue('status', 'canceled'));
        $this->assertSame('Pendiente', AuditPresenter::translateFieldValue('status', 'pending'));
        $this->assertSame('Anulado', AuditPresenter::translateFieldValue('status', 'voided'));
    }

    public function test_translate_unknown_status_capitalizes(): void
    {
        $this->assertSame('Custom', AuditPresenter::translateFieldValue('status', 'custom'));
    }

    public function test_translate_periodicity_values(): void
    {
        $this->assertSame('Semanal', AuditPresenter::translateFieldValue('periodicity', 'weekly'));
        $this->assertSame('Quincenal', AuditPresenter::translateFieldValue('periodicity', 'biweekly'));
        $this->assertSame('Mensual', AuditPresenter::translateFieldValue('periodicity', 'monthly'));
        $this->assertSame('Diario', AuditPresenter::translateFieldValue('periodicity', 'daily'));
    }

    public function test_translate_money_fields(): void
    {
        // Format::money returns a currency-formatted string
        $result = AuditPresenter::translateFieldValue('amount', 5000);
        $this->assertIsString($result);
        $this->assertNotSame('5000', $result); // Should be formatted, not raw

        $result = AuditPresenter::translateFieldValue('balance', 1500.50);
        $this->assertIsString($result);
    }

    public function test_translate_date_fields(): void
    {
        $result = AuditPresenter::translateFieldValue('start_date', '2026-03-15');
        $this->assertSame('15/03/2026', $result);

        $result = AuditPresenter::translateFieldValue('payment_date', '2026-01-01');
        $this->assertSame('01/01/2026', $result);
    }

    public function test_translate_datetime_fields(): void
    {
        $result = AuditPresenter::translateFieldValue('executed_at', '2026-02-09T14:30:45.123456Z');
        $this->assertStringContainsString('09/02/2026', $result);
        $this->assertStringContainsString('14:30', $result);
    }

    public function test_translate_mode_values(): void
    {
        $this->assertSame('A nivel de crédito', AuditPresenter::translateFieldValue('mode', 'credit_first'));
        $this->assertSame('A nivel de cuota', AuditPresenter::translateFieldValue('mode', 'installment_first'));
    }

    public function test_translate_is_locked(): void
    {
        $this->assertSame('Sí', AuditPresenter::translateFieldValue('is_locked', true));
        $this->assertSame('No', AuditPresenter::translateFieldValue('is_locked', false));
    }

    public function test_translate_array_value_returns_json(): void
    {
        $result = AuditPresenter::translateFieldValue('some_field', ['a' => 1]);
        $this->assertSame('{"a":1}', $result);
    }

    public function test_translate_plain_string(): void
    {
        $this->assertSame('hello', AuditPresenter::translateFieldValue('unknown_field', 'hello'));
    }

    // =========================================================================
    // computeChanges
    // =========================================================================

    public function test_compute_changes_both_null(): void
    {
        $changes = AuditPresenter::computeChanges(null, null);
        $this->assertSame([], $changes);
    }

    public function test_compute_changes_creation(): void
    {
        $after = [
            'amount' => 5000,
            'status' => 'active',
            'periodicity' => 'monthly',
        ];

        $changes = AuditPresenter::computeChanges(null, $after);

        $this->assertCount(3, $changes);

        // Verify structure
        foreach ($changes as $change) {
            $this->assertArrayHasKey('key', $change);
            $this->assertArrayHasKey('label', $change);
            $this->assertArrayHasKey('before', $change);
            $this->assertArrayHasKey('after', $change);
            $this->assertNull($change['before']);
            $this->assertNotNull($change['after']);
        }
    }

    public function test_compute_changes_deletion(): void
    {
        $before = [
            'amount' => 5000,
            'status' => 'active',
        ];

        $changes = AuditPresenter::computeChanges($before, null);

        $this->assertCount(2, $changes);

        foreach ($changes as $change) {
            $this->assertNotNull($change['before']);
            $this->assertNull($change['after']);
        }
    }

    public function test_compute_changes_update_shows_only_differences(): void
    {
        $before = [
            'amount' => 5000,
            'status' => 'active',
            'periodicity' => 'monthly',
        ];
        $after = [
            'amount' => 7000,
            'status' => 'active', // unchanged
            'periodicity' => 'weekly',
        ];

        $changes = AuditPresenter::computeChanges($before, $after);

        // status didn't change, so only 2 changes
        $this->assertCount(2, $changes);

        $keys = array_column($changes, 'key');
        $this->assertContains('amount', $keys);
        $this->assertContains('periodicity', $keys);
        $this->assertNotContains('status', $keys);
    }

    public function test_compute_changes_excludes_internal_fields(): void
    {
        $before = [
            'id' => 1,
            'company_id' => 10,
            'created_at' => '2026-01-01',
            'updated_at' => '2026-01-02',
            'amount' => 5000,
        ];
        $after = [
            'id' => 1,
            'company_id' => 10,
            'created_at' => '2026-01-01',
            'updated_at' => '2026-02-01',
            'amount' => 7000,
        ];

        $changes = AuditPresenter::computeChanges($before, $after);

        $keys = array_column($changes, 'key');
        $this->assertNotContains('id', $keys);
        $this->assertNotContains('company_id', $keys);
        $this->assertNotContains('created_at', $keys);
        $this->assertNotContains('updated_at', $keys);
        $this->assertContains('amount', $keys);
    }

    public function test_compute_changes_skips_arrays(): void
    {
        $before = [
            'amount' => 5000,
            'installments' => [['id' => 1], ['id' => 2]],
        ];
        $after = [
            'amount' => 7000,
            'installments' => [['id' => 1], ['id' => 2], ['id' => 3]],
        ];

        $changes = AuditPresenter::computeChanges($before, $after);

        $keys = array_column($changes, 'key');
        $this->assertContains('amount', $keys);
        $this->assertNotContains('installments', $keys);
    }

    public function test_compute_changes_translates_labels(): void
    {
        $before = ['amount' => 5000];
        $after = ['amount' => 7000];

        $changes = AuditPresenter::computeChanges($before, $after);

        $this->assertSame('Monto', $changes[0]['label']);
    }

    public function test_compute_changes_formats_values(): void
    {
        $before = ['status' => 'active'];
        $after = ['status' => 'paid'];

        $changes = AuditPresenter::computeChanges($before, $after);

        $this->assertSame('Activo', $changes[0]['before']);
        $this->assertSame('Pagado', $changes[0]['after']);
    }

    // =========================================================================
    // translateDataBlock
    // =========================================================================

    public function test_translate_data_block_with_input(): void
    {
        $data = [
            'input' => [
                'amount' => 5000,
                'periodicity' => 'monthly',
                'reason' => 'Solicitud del cliente',
            ],
            'new_credit_id' => 456,
            'executed_at' => '2026-02-09T14:30:00Z',
        ];

        $result = AuditPresenter::translateDataBlock($data);

        $this->assertArrayHasKey('Monto', $result);
        $this->assertArrayHasKey('Periodicidad', $result);
        $this->assertSame('Mensual', $result['Periodicidad']);
        $this->assertArrayHasKey('Motivo', $result);
        $this->assertSame('Solicitud del cliente', $result['Motivo']);
        $this->assertArrayHasKey('Crédito generado', $result);
        $this->assertSame('456', $result['Crédito generado']);
        $this->assertArrayHasKey('Fecha de ejecución', $result);
    }

    public function test_translate_data_block_empty(): void
    {
        $result = AuditPresenter::translateDataBlock([]);
        $this->assertSame([], $result);
    }

    public function test_translate_data_block_excludes_arrays_in_input(): void
    {
        $data = [
            'input' => [
                'amount' => 5000,
                'nested_array' => ['a', 'b', 'c'],
            ],
        ];

        $result = AuditPresenter::translateDataBlock($data);

        $this->assertArrayHasKey('Monto', $result);
        $this->assertCount(1, $result); // nested_array excluded
    }

    public function test_translate_data_block_excludes_internal_keys(): void
    {
        $data = [
            'input' => [
                'company_id' => 1,
                'created_at' => '2026-01-01',
                'amount' => 5000,
            ],
        ];

        $result = AuditPresenter::translateDataBlock($data);

        $this->assertArrayNotHasKey('company_id', $result);
        $this->assertArrayHasKey('Monto', $result);
    }
}
