<?php

namespace Tests\Feature\Unit;

use App\Models\User;
use App\Models\WalletBalance;
use App\Services\WalletService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use RuntimeException;
use Tests\TestCase;

class WalletServiceTest extends TestCase
{
    use RefreshDatabase;

    public function test_wallet_credit_and_debit_are_consistent(): void
    {
        $user = User::query()->create([
            'member_code' => 'AKRTEST001',
            'referral_code' => 'REFTEST001',
            'name' => 'Wallet User',
            'email' => 'wallet@example.com',
            'mobile' => '9000000001',
            'password' => 'password',
            'role' => 'user',
            'status' => 'active',
        ]);

        $service = app(WalletService::class);
        $service->credit($user->id, 'withdrawable', 1000, 'test_credit');
        $service->debit($user->id, 'withdrawable', 200, 'test_debit');

        $balance = WalletBalance::query()->where('user_id', $user->id)->firstOrFail();
        $this->assertSame('800.00', $balance->withdrawable_balance);
    }

    public function test_wallet_prevents_negative_balances(): void
    {
        $user = User::query()->create([
            'member_code' => 'AKRTEST002',
            'referral_code' => 'REFTEST002',
            'name' => 'Wallet User 2',
            'email' => 'wallet2@example.com',
            'mobile' => '9000000002',
            'password' => 'password',
            'role' => 'user',
            'status' => 'active',
        ]);

        $this->expectException(RuntimeException::class);
        app(WalletService::class)->debit($user->id, 'withdrawable', 10, 'test_debit');

        $this->fail('Expected RuntimeException for negative balance.');
    }

    public function test_wallet_randomized_credit_debit_sequence_matches_balance(): void
    {
        $user = User::query()->create([
            'member_code' => 'AKRTEST003',
            'referral_code' => 'REFTEST003',
            'name' => 'Wallet User 3',
            'email' => 'wallet3@example.com',
            'mobile' => '9000000003',
            'password' => 'password',
            'role' => 'user',
            'status' => 'active',
        ]);

        $service = app(WalletService::class);
        $expected = 0.0;
        mt_srand(1234);

        for ($i = 0; $i < 100; $i++) {
            $amount = (float) mt_rand(10, 500);
            $doDebit = mt_rand(0, 1) === 1;

            if ($doDebit && $expected >= $amount) {
                $service->debit($user->id, 'withdrawable', $amount, 'test_debit');
                $expected = round($expected - $amount, 2);
            } else {
                $service->credit($user->id, 'withdrawable', $amount, 'test_credit');
                $expected = round($expected + $amount, 2);
            }
        }

        $balance = WalletBalance::query()->where('user_id', $user->id)->firstOrFail();
        $this->assertSame(number_format($expected, 2, '.', ''), $balance->withdrawable_balance);
    }
}
