<?php

namespace Tests\Feature;

use App\Enums\UserKycStatus;
use App\Mail\ConfirmInvestmentMail;
use App\Models\InvestmentSetting;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;

class KycInvestorAccessTest extends TestCase
{
    use RefreshDatabase;

    public function test_investor_without_kyc_can_view_dashboard_balances_and_settings(): void
    {
        $user = User::factory()->kycAwaitingSubmission()->create();

        $this->actingAs($user)->get(route('dashboard'))->assertOk();
        $this->actingAs($user)->get(route('balances.index'))->assertOk();
        $this->actingAs($user)->get(route('balances.wallets'))->assertOk();
        $this->actingAs($user)->get(route('profile.edit'))->assertOk();
        $this->actingAs($user)->get(route('kyc.show'))->assertOk();
    }

    public function test_pending_kyc_blocks_investment_store_wallet_store_and_withdrawal_store(): void
    {
        InvestmentSetting::current();

        $user = User::factory()->kycAwaitingSubmission()->create();

        $this->actingAs($user)
            ->post(route('investments.store'), [
                'funding_source' => 'blockchain',
                'amount' => 400,
                'duration_months' => 4,
                'txid' => 'tx-sensitive',
            ])
            ->assertRedirect(route('kyc.show'));

        $this->assertDatabaseMissing('investments', ['user_id' => $user->id]);

        $this->actingAs($user)
            ->post(route('balances.withdrawals.store'), [])
            ->assertRedirect(route('kyc.show'));

        $this->actingAs($user)
            ->post(route('balances.wallets.store'), [
                'currency_network' => 'TRC20',
                'address' => 'TDummyNoSave',
                'label' => null,
                'is_default' => true,
            ])
            ->assertRedirect(route('kyc.show'));

        $this->assertDatabaseMissing('user_wallets', ['user_id' => $user->id]);
    }

    public function test_investor_can_register_investment_after_kyc_approval(): void
    {
        InvestmentSetting::current();

        $user = User::factory()->kycAwaitingSubmission()->create();

        $user->forceFill([
            'kyc_status' => UserKycStatus::Approved,
            'kyc_rejection_reason' => null,
        ])->save();

        Mail::fake();

        $response = $this->actingAs($user)->post(route('investments.store'), [
            'funding_source' => 'blockchain',
            'amount' => 500,
            'duration_months' => 4,
            'txid' => 'tx-after-kyc',
        ]);

        $response->assertRedirect(route('investments.index'));

        $this->assertDatabaseMissing('investments', [
            'user_id' => $user->id,
        ]);

        $confirmUrl = null;
        Mail::assertSent(ConfirmInvestmentMail::class, function (ConfirmInvestmentMail $mail) use (&$confirmUrl): bool {
            $confirmUrl = $mail->confirmUrl;

            return true;
        });
        $this->assertSame(1, preg_match('#/confirmaciones/correo/inversion/([a-fA-F0-9]+)#', (string) $confirmUrl, $matches));

        $this->actingAs($user)
            ->get(route('confirm.email.investment', ['token' => $matches[1]]))
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('confirmations/investment')
                ->where('pending_approval', true));

        $this->assertDatabaseHas('investments', [
            'user_id' => $user->id,
            'txid' => 'tx-after-kyc',
        ]);
    }

    public function test_investor_without_kyc_can_invest_when_policy_disables_kyc_gate(): void
    {
        InvestmentSetting::current()->forceFill([
            'require_kyc_to_invest' => false,
        ])->save();

        InvestmentSetting::current()->refresh();

        $user = User::factory()->kycAwaitingSubmission()->create();

        Mail::fake();

        $this->actingAs($user)
            ->post(route('investments.store'), [
                'funding_source' => 'blockchain',
                'amount' => 400,
                'duration_months' => 4,
                'txid' => 'tx-no-kyc-invest-flag',
            ])
            ->assertRedirect(route('investments.index'));

        $this->assertDatabaseMissing('investments', [
            'user_id' => $user->id,
        ]);

        $confirmUrl = null;
        Mail::assertSent(ConfirmInvestmentMail::class, function (ConfirmInvestmentMail $mail) use (&$confirmUrl): bool {
            $confirmUrl = $mail->confirmUrl;

            return true;
        });
        $this->assertSame(1, preg_match('#/confirmaciones/correo/inversion/([a-fA-F0-9]+)#', (string) $confirmUrl, $matches));

        $this->actingAs($user)
            ->get(route('confirm.email.investment', ['token' => $matches[1]]))
            ->assertOk()
            ->assertInertia(fn ($page) => $page
                ->component('confirmations/investment')
                ->where('pending_approval', true));

        $this->assertDatabaseHas('investments', [
            'user_id' => $user->id,
            'txid' => 'tx-no-kyc-invest-flag',
        ]);
    }

    public function test_admin_accounts_skip_kyc_gate(): void
    {
        $admin = User::factory()->kycAwaitingSubmission()->admin()->create([
            'email' => 'ops@example.com',
        ]);

        $this->assertTrue($admin->is_admin);

        $this->actingAs($admin)->get(route('dashboard'))->assertOk();
    }
}
