<?php

use App\Models\AdminUser;
use App\Models\Player;
use App\Models\TransferOrder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->artisan('lottery:admin-auth-sync')->assertExitCode(0);
});

test('orphan players can be backfilled to site root agent', function (): void {
    $siteId = (int) DB::table('admin_sites')->where('is_default', true)->value('id');
    $siteCode = (string) DB::table('admin_sites')->where('id', $siteId)->value('code');
    $rootId = (int) DB::table('agent_nodes')->where('admin_site_id', $siteId)->where('depth', 0)->value('id');

    $playerId = Player::query()->create([
        'site_code' => $siteCode,
        'site_player_id' => 'orphan-1',
        'username' => 'orphan',
        'nickname' => null,
        'default_currency' => 'NPR',
        'status' => 0,
        'agent_node_id' => null,
    ])->id;

    DB::table('players')
        ->where('site_code', $siteCode)
        ->whereNull('agent_node_id')
        ->update(['agent_node_id' => $rootId]);

    expect((int) Player::query()->find($playerId)?->agent_node_id)->toBe($rootId);
});

test('transfer list excludes players outside agent subtree', function (): void {
    $siteId = (int) DB::table('admin_sites')->where('is_default', true)->value('id');
    $siteCode = (string) DB::table('admin_sites')->where('id', $siteId)->value('code');
    $rootId = (int) DB::table('agent_nodes')->where('admin_site_id', $siteId)->where('depth', 0)->value('id');
    $service = app(\App\Services\Agent\AgentNodeService::class);
    $super = AdminUser::query()->create([
        'username' => 'bind_super',
        'name' => 'Super',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($super);

    $branch = $service->createChild($super, ['parent_id' => $rootId, 'code' => 'bind-a', 'name' => 'A']);
    $other = $service->createChild($super, ['parent_id' => $rootId, 'code' => 'bind-b', 'name' => 'B']);

    $inPlayer = Player::query()->create([
        'site_code' => $siteCode,
        'agent_node_id' => $branch->id,
        'site_player_id' => 'bind-in',
        'username' => 'bind_in',
        'nickname' => null,
        'default_currency' => 'NPR',
        'status' => 0,
    ]);
    $outPlayer = Player::query()->create([
        'site_code' => $siteCode,
        'agent_node_id' => $other->id,
        'site_player_id' => 'bind-out',
        'username' => 'bind_out',
        'nickname' => null,
        'default_currency' => 'NPR',
        'status' => 0,
    ]);

    foreach ([$inPlayer, $outPlayer] as $index => $player) {
        TransferOrder::query()->create([
            'transfer_no' => 'TR-BIND-'.$index,
            'player_id' => $player->id,
            'direction' => 'in',
            'currency_code' => 'NPR',
            'amount' => 100,
            'status' => 'completed',
            'idempotent_key' => 'idem-bind-'.$index,
            'external_ref_no' => 'ext-'.$index,
            'fail_reason' => null,
            'created_at' => now(),
            'updated_at' => now(),
            'finished_at' => now(),
        ]);
    }

    $operator = AdminUser::query()->create([
        'username' => 'bind_ops',
        'name' => 'Ops',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantAgentOpsForBinding($operator, $branch);

    $token = $operator->createToken('test', ['*'], now()->addDay())->plainTextToken;

    $response = $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/wallet/transfer-orders?site_code='.$siteCode);

    $response->assertOk();
    $playerIds = collect($response->json('data.items'))->pluck('player_id')->map(static fn ($id): int => (int) $id);
    expect($playerIds)->toContain($inPlayer->id)->not->toContain($outPlayer->id);
});

function grantAgentOpsForBinding(AdminUser $admin, \App\Models\AgentNode $agent): void
{
    $now = now();
    $roleId = DB::table('admin_roles')->insertGetId([
        'slug' => 'bind_ops_'.$admin->id,
        'code' => 'bind_ops_'.$admin->id,
        'name' => 'Bind Ops',
        'scope_type' => 'system',
        'status' => 1,
        'is_system' => false,
        'sort_order' => 0,
        'created_at' => $now,
        'updated_at' => $now,
    ]);

    foreach (['agent.node.view', 'service.wallet.view', 'service.reconcile.view'] as $code) {
        $actionId = DB::table('admin_menu_actions')->where('permission_code', $code)->value('id');
        if ($actionId) {
            DB::table('admin_role_menu_actions')->insert([
                'role_id' => $roleId,
                'menu_action_id' => (int) $actionId,
            ]);
        }
    }

    DB::table('admin_user_site_roles')->insert([
        'admin_user_id' => $admin->id,
        'site_id' => (int) $agent->admin_site_id,
        'role_id' => $roleId,
        'granted_at' => $now,
    ]);

    DB::table('admin_user_agents')->insert([
        'admin_user_id' => $admin->id,
        'agent_node_id' => (int) $agent->id,
        'is_primary' => true,
        'granted_at' => $now,
    ]);
}
