<?php

namespace Tests\Feature\Admin;

use App\Enums\AccrualFrequency;
use App\Enums\InvestmentStatus;
use App\Enums\InvestmentTransactionType;
use App\Models\Investment;
use App\Models\InvestmentSetting;
use App\Models\InvestmentTransaction;
use App\Models\User;
use App\Support\InvestmentLedger;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AdminDebugAuditTest extends TestCase
{
    use RefreshDatabase;

    public function test_debug_audit_page_is_hidden_when_adjustments_disabled(): void
    {
        config(['app.allow_adjustments' => false]);

        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->get(route('admin.debug.index'))
            ->assertNotFound();
    }

    public function test_debug_audit_page_stays_hidden_when_only_app_debug_is_true(): void
    {
        config([
            'app.debug' => true,
            'app.allow_adjustments' => false,
        ]);

        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->get(route('admin.debug.index'))
            ->assertNotFound();
    }

    public function test_debug_audit_page_renders_shell_without_blocking_data(): void
    {
        config(['app.allow_adjustments' => true]);

        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->get(route('admin.debug.index'))
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('admin/debug-audit')
                ->has('summary')
                ->has('balance_inconsistencies')
                ->has('manual_balance_credits')
                ->has('accrual_inconsistencies'));
    }

    public function test_debug_audit_sections_return_paginated_json(): void
    {
        config(['app.allow_adjustments' => true]);

        InvestmentSetting::current()->update([
            'monthly_return' => 5,
            'accrual_frequency' => AccrualFrequency::Monthly->value,
            'accrual_day_of_month' => 30,
        ]);

        $admin = User::factory()->admin()->create();
        $investor = User::factory()->create();

        /** @var Investment $investment */
        $investment = $investor->investments()->create([
            'amount' => 200,
            'duration_months' => 6,
            'monthly_return_snapshot' => 5,
            'txid' => 'IMP-FX-debug-audit',
            'status' => InvestmentStatus::Active,
            'confirmed_at' => Carbon::parse('2026-05-01'),
            'maturity_at' => Carbon::parse('2026-11-01'),
            'confirmed_by' => $admin->id,
            'capital_balance' => 999,
        ]);

        InvestmentTransaction::query()->create([
            'investment_id' => $investment->id,
            'type' => InvestmentTransactionType::Deposit,
            'amount' => 200,
            'balance_after' => 200,
        ]);

        InvestmentTransaction::query()->create([
            'investment_id' => $investment->id,
            'type' => InvestmentTransactionType::PeriodAccrual,
            'amount' => 4,
            'balance_after' => 204,
            'applied_percent' => 2,
            'accrual_on' => '2026-05-30',
            'gain_period_start' => '2026-05-01',
            'gain_period_end' => '2026-05-30',
        ]);

        InvestmentLedger::applyAdminBalanceCredit($investor, 25, 'Prueba debug', $admin->id);

        $this->actingAs($admin)
            ->getJson(route('admin.debug.sections.investments'))
            ->assertOk()
            ->assertJsonPath('total', fn ($total) => $total >= 1)
            ->assertJsonPath('per_page', 15)
            ->assertJsonStructure(['data', 'current_page', 'last_page']);

        $this->actingAs($admin)
            ->getJson(route('admin.debug.sections.manual-credits'))
            ->assertOk()
            ->assertJsonPath('total', 1)
            ->assertJsonCount(1, 'data');

        $this->actingAs($admin)
            ->getJson(route('admin.debug.sections.accruals'))
            ->assertOk()
            ->assertJsonPath('total', 1)
            ->assertJsonCount(1, 'data');
    }

    public function test_debug_audit_excludes_accruals_with_intentional_admin_rate(): void
    {
        config(['app.allow_adjustments' => true]);

        InvestmentSetting::current()->update([
            'monthly_return' => 8,
            'accrual_frequency' => AccrualFrequency::Monthly->value,
            'accrual_day_of_month' => 30,
        ]);

        $admin = User::factory()->admin()->create();
        $investor = User::factory()->create();

        /** @var Investment $investment */
        $investment = $investor->investments()->create([
            'amount' => 200,
            'duration_months' => 6,
            'monthly_return_snapshot' => 5,
            'txid' => 'tx-admin-rate-override',
            'status' => InvestmentStatus::Active,
            'confirmed_at' => Carbon::parse('2026-05-01'),
            'maturity_at' => Carbon::parse('2026-11-01'),
            'confirmed_by' => $admin->id,
            'capital_balance' => 200,
        ]);

        InvestmentTransaction::query()->create([
            'investment_id' => $investment->id,
            'type' => InvestmentTransactionType::Deposit,
            'amount' => 200,
            'balance_after' => 200,
        ]);

        $this->assertSame(1, InvestmentLedger::runAccrualForDate(Carbon::parse('2026-05-30')));

        $period = InvestmentTransaction::query()
            ->where('investment_id', $investment->id)
            ->where('type', InvestmentTransactionType::PeriodAccrual)
            ->first();

        $this->assertNotNull($period);
        $this->assertTrue(InvestmentLedger::periodAccrualIsIntentionalAdminRateExecution($period));

        $this->actingAs($admin)
            ->getJson(route('admin.debug.sections.accruals'))
            ->assertOk()
            ->assertJsonPath('total', 0)
            ->assertJsonCount(0, 'data');
    }

    public function test_debug_section_endpoints_are_hidden_when_adjustments_disabled(): void
    {
        config(['app.allow_adjustments' => false]);

        $admin = User::factory()->admin()->create();

        $this->actingAs($admin)
            ->getJson(route('admin.debug.sections.investments'))
            ->assertNotFound();
    }

    public function test_debug_manual_balance_revert_redirects_to_debug_page(): void
    {
        config(['app.allow_adjustments' => true]);

        $admin = User::factory()->admin()->create();
        $investor = User::factory()->create();

        $credit = InvestmentLedger::applyAdminBalanceCredit($investor, 15, 'Revertir desde debug', $admin->id);

        $this->actingAs($admin)
            ->post(route('admin.debug.manual-balance.revert', [
                'user' => $investor->id,
                'transaction' => $credit->id,
            ]))
            ->assertRedirect(route('admin.debug.index'));
    }

    public function test_debug_balance_consolidation_section_lists_users_with_dispersed_withdrawable(): void
    {
        config(['app.allow_adjustments' => true]);

        $admin = User::factory()->admin()->create();
        $investor = User::factory()->create();

        /** @var Investment $investment */
        $investment = $investor->investments()->create([
            'amount' => 300,
            'duration_months' => 6,
            'monthly_return_snapshot' => 5,
            'txid' => 'tx-consolidate-audit',
            'status' => InvestmentStatus::Active,
            'confirmed_at' => now(),
            'confirmed_by' => $admin->id,
            'capital_balance' => 300,
        ]);

        InvestmentTransaction::query()->create([
            'investment_id' => $investment->id,
            'type' => InvestmentTransactionType::Deposit,
            'amount' => 300,
            'balance_after' => 300,
        ]);

        $this->actingAs($admin)
            ->getJson(route('admin.debug.sections.balance-consolidation'))
            ->assertOk()
            ->assertJsonPath('total', 1)
            ->assertJsonPath('data.0.user_id', $investor->id)
            ->assertJsonPath('data.0.amount_to_move_usd', '300.00');

        $this->actingAs($admin)
            ->getJson(route('admin.debug.consolidate-balance.preview', [
                'user_ids' => [$investor->id],
            ]))
            ->assertOk()
            ->assertJsonPath('user_count', 1)
            ->assertJsonPath('total_amount_to_move_usd', '300.00')
            ->assertJsonCount(1, 'users.0.actions');

        $this->actingAs($admin)
            ->post(route('admin.debug.consolidate-balance'), [
                'user_ids' => [$investor->id],
            ])
            ->assertRedirect(route('admin.debug.index'));

        $investment->refresh();
        $this->assertSame('0.00', (string) $investment->capital_balance);

        $container = Investment::query()
            ->where('txid', InvestmentLedger::ADMIN_CREDIT_TXID_PREFIX.$investor->id)
            ->firstOrFail();

        $this->assertSame('300.00', (string) $container->capital_balance);

        $this->actingAs($admin)
            ->getJson(route('admin.debug.sections.balance-consolidation'))
            ->assertOk()
            ->assertJsonPath('total', 0);
    }
}
