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

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

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

        $this->actingAs($admin)
            ->post(route('admin.platform-accrual.void-run', ['runDate' => '2026-06-29']), [
                'mode' => 'period',
            ])
            ->assertNotFound();
    }

    public function test_debug_mode_voids_monthly_run_gains_without_touching_approval_referrals(): void
    {
        config(['app.allow_adjustments' => true]);
        InvestmentSetting::current()->update([
            'monthly_return' => 10,
            'accrual_frequency' => AccrualFrequency::Monthly->value,
            'accrual_day_of_month' => 29,
            'referral_direct_percent' => 7,
        ]);

        $admin = User::factory()->admin()->create();
        $referrer = User::factory()->create(['referral_program_enabled' => true]);
        $investor = User::factory()->create(['referred_by_user_id' => $referrer->id]);

        $investment = $this->seedInvestment($investor, $admin);
        InvestmentLedger::creditReferralBonusesOnInvestmentApproval($investment);

        $deposit = InvestmentTransaction::query()
            ->where('investment_id', $investment->id)
            ->where('type', InvestmentTransactionType::Deposit)
            ->firstOrFail();

        InvestmentLedger::runAccrualForDate(Carbon::parse('2026-06-29'));

        $this->assertDatabaseHas('investment_transactions', [
            'investment_id' => $investment->id,
            'type' => InvestmentTransactionType::PeriodAccrual->value,
        ]);

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

        $this->assertDatabaseMissing('investment_transactions', [
            'beneficiary_user_id' => $referrer->id,
            'type' => InvestmentTransactionType::ReferralDirectBonus->value,
            'referral_source_transaction_id' => $gain->id,
        ]);

        $this->assertDatabaseHas('investment_transactions', [
            'beneficiary_user_id' => $referrer->id,
            'type' => InvestmentTransactionType::ReferralDirectBonus->value,
            'referral_source_transaction_id' => $deposit->id,
        ]);

        $investment->refresh();
        $this->assertGreaterThan(200, (float) $investment->capital_balance);

        $this->actingAs($admin)
            ->post(route('admin.platform-accrual.void-run', ['runDate' => '2026-06-29']), [
                'mode' => 'period',
            ])
            ->assertRedirect(route('admin.platform-accrual.index'));

        $investment->refresh();

        $this->assertSame(200.0, (float) $investment->capital_balance);
        $this->assertNull($investment->accrual_through_date);
        $this->assertDatabaseMissing('investment_transactions', ['id' => $gain->id]);
        $this->assertDatabaseHas('investment_transactions', [
            'beneficiary_user_id' => $referrer->id,
            'referral_source_transaction_id' => $deposit->id,
        ]);
    }

    public function test_accrual_run_detail_exposes_void_action_in_debug_for_period_mode(): void
    {
        config(['app.allow_adjustments' => true]);
        InvestmentSetting::current()->update([
            'monthly_return' => 3.5,
            'accrual_frequency' => AccrualFrequency::Monthly->value,
            'accrual_day_of_month' => 29,
        ]);

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

        InvestmentLedger::runAccrualForDate(Carbon::parse('2026-06-29'));

        $this->actingAs($admin)
            ->get(route('admin.platform-accrual.show', [
                'runDate' => '2026-06-29',
                'mode' => 'period',
            ]))
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('admin/platform-monthly-accrual-detail')
                ->where('adjustments_enabled', true)
                ->where('run.mode', 'period')
                ->where('run.tx_count', 1));
    }

    public function test_investment_accrual_detail_still_shows_period_label(): void
    {
        config(['app.allow_adjustments' => true]);
        InvestmentSetting::current()->update([
            'monthly_return' => 3.5,
            'accrual_frequency' => AccrualFrequency::Monthly->value,
            'accrual_day_of_month' => 29,
        ]);

        $admin = User::factory()->admin()->create();
        $investor = User::factory()->create();
        $investment = $this->seedInvestment($investor, $admin);

        InvestmentLedger::runAccrualForDate(Carbon::parse('2026-06-29'));

        $this->actingAs($admin)
            ->get(route('admin.investments.accruals', $investment))
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->where('lines.0.period_label', 'Junio 1-30'));
    }

    private function seedInvestment(User $investor, User $admin): Investment
    {
        /** @var Investment $investment */
        $investment = $investor->investments()->create([
            'amount' => 200,
            'duration_months' => 6,
            'monthly_return_snapshot' => 3.5,
            'txid' => 'tx-platform-void',
            'status' => InvestmentStatus::Active,
            'confirmed_at' => Carbon::parse('2026-06-01'),
            'maturity_at' => Carbon::parse('2026-12-01'),
            'confirmed_by' => $admin->id,
            'capital_balance' => 200,
        ]);

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

        return $investment;
    }
}
