<?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 PlatformAccrualRecalculateTest extends TestCase
{
    use RefreshDatabase;

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

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

        $this->actingAs($admin)
            ->getJson(route('admin.platform-accrual.recalculate-preview', $txn))
            ->assertNotFound();

        $this->actingAs($admin)
            ->post(route('admin.platform-accrual.recalculate-apply', $txn))
            ->assertNotFound();
    }

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

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

        $response = $this->actingAs($admin)
            ->getJson(route('admin.platform-accrual.recalculate-preview', $txn))
            ->assertOk()
            ->json();

        $this->assertTrue($response['needs_change']);
        $this->assertSame('2026-05-01', $response['current']['period_start']);
        $this->assertSame('2026-05-30', $response['current']['period_end']);
        $this->assertSame('2026-05-01', $response['proposed']['period_start']);
        $this->assertSame('2026-05-31', $response['proposed']['period_end']);
        $this->assertSame('5.00', $response['proposed']['plan_percent']);
        $this->assertSame('10.00', $response['proposed']['gain_usd']);
    }

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

        $admin = User::factory()->admin()->create();
        $txn = $this->seedWrongPeriodAccrual();
        $investment = Investment::query()->findOrFail($txn->investment_id);

        $this->actingAs($admin)
            ->post(route('admin.platform-accrual.recalculate-apply', $txn))
            ->assertRedirect(route('admin.platform-accrual.show', [
                'runDate' => '2026-05-30',
                'mode' => 'period',
            ]));

        $txn->refresh();
        $investment->refresh();

        $this->assertSame('2026-05-31', $txn->gain_period_end?->toDateString());
        $this->assertSame('10.00', number_format((float) $txn->amount, 2, '.', ''));
        $this->assertSame('210.00', number_format((float) $investment->capital_balance, 2, '.', ''));
        $this->assertSame('210.00', number_format((float) $txn->balance_after, 2, '.', ''));
    }

    private function seedWrongPeriodAccrual(): InvestmentTransaction
    {
        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-test-recalc',
            'status' => InvestmentStatus::Active,
            'confirmed_at' => Carbon::parse('2026-05-01'),
            'maturity_at' => Carbon::parse('2026-11-01'),
            'confirmed_by' => $admin->id,
            'capital_balance' => 204,
        ]);

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

        return 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',
        ]);
    }
}
