<?php

use App\Models\AdminUser;
use App\Models\AgentNode;
use App\Models\Draw;
use App\Models\Player;
use App\Models\TicketItem;
use App\Models\TicketOrder;
use App\Lottery\DrawStatus;
use App\Services\Admin\AdminReportQueryService;
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('player win loss report 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' => 'rpt_super',
        'name' => 'Super',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($super);

    $branch = $service->createChild($super, [
        'parent_id' => $rootId,
        'code' => 'rpt-branch',
        'name' => 'Report Branch',
    ]);
    $otherBranch = $service->createChild($super, [
        'parent_id' => $rootId,
        'code' => 'rpt-other',
        'name' => 'Other Branch',
    ]);

    $today = now()->toDateString();
    $draw = Draw::query()->create([
        'draw_no' => 'RPT-'.now()->format('YmdHis'),
        'business_date' => $today,
        'sequence_no' => 901,
        'status' => DrawStatus::Open->value,
        'start_time' => now()->subMinute(),
        'close_time' => now()->addHour(),
        'draw_time' => now()->addHours(2),
        'cooling_end_time' => null,
        'result_source' => null,
        'current_result_version' => 0,
        'settle_version' => 0,
        'is_reopened' => false,
    ]);

    $inScope = Player::query()->create([
        'site_code' => $siteCode,
        'site_player_id' => 'rpt-in',
        'username' => 'rpt_in',
        'nickname' => null,
        'default_currency' => 'NPR',
        'status' => 0,
        'agent_node_id' => $branch->id,
    ]);
    $outScope = Player::query()->create([
        'site_code' => $siteCode,
        'site_player_id' => 'rpt-out',
        'username' => 'rpt_out',
        'nickname' => null,
        'default_currency' => 'NPR',
        'status' => 0,
        'agent_node_id' => $otherBranch->id,
    ]);

    foreach ([$inScope, $outScope] as $index => $player) {
        $order = TicketOrder::query()->create([
            'order_no' => 'RPT-ORD-'.$index,
            'player_id' => $player->id,
            'draw_id' => $draw->id,
            'currency_code' => 'NPR',
            'total_bet_amount' => 1000,
            'total_rebate_amount' => 0,
            'total_actual_deduct' => 1000,
            'total_estimated_payout' => 0,
            'status' => 'placed',
            'submit_source' => 'h5',
            'client_trace_id' => 'rpt-trace-'.$index,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
        TicketItem::query()->create([
            'ticket_no' => 'RPT-TK-'.$index,
            'order_id' => $order->id,
            'player_id' => $player->id,
            'draw_id' => $draw->id,
            'original_number' => '1234',
            'normalized_number' => '1234',
            'play_code' => 'big',
            'dimension' => 4,
            'digit_slot' => null,
            'bet_mode' => 'single',
            'unit_bet_amount' => 1000,
            'total_bet_amount' => 1000,
            'rebate_rate_snapshot' => '0.0000',
            'commission_rate_snapshot' => '0.0000',
            'actual_deduct_amount' => 1000,
            'win_amount' => 0,
            'jackpot_win_amount' => 0,
            'status' => 'placed',
        ]);
    }

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

    $query = app(AdminReportQueryService::class);
    $scoped = $query->playerWinLossPaginated(null, $today, $today, 1, 20, $operator);
    $all = $query->playerWinLossPaginated(null, $today, $today, 1, 20, null);

    $scopedUsernames = collect($scoped->items())->pluck('username')->all();
    $allUsernames = collect($all->items())->pluck('username')->all();

    expect($scopedUsernames)->toContain('rpt_in')->not->toContain('rpt_out')
        ->and($allUsernames)->toContain('rpt_in', 'rpt_out');
});

function grantReportAgentManager(AdminUser $admin, AgentNode $agent): void
{
    $now = now();
    $roleId = DB::table('admin_roles')->insertGetId([
        'slug' => 'rpt_mgr_'.$admin->id,
        'code' => 'rpt_mgr_'.$admin->id,
        'name' => 'Report Manager',
        'scope_type' => 'system',
        'status' => 1,
        'is_system' => false,
        'sort_order' => 0,
        'created_at' => $now,
        'updated_at' => $now,
    ]);

    $codes = ['agent.node.view', 'agent.node.manage', 'service.players.view', 'service.report.view'];
    $actionIds = DB::table('admin_menu_actions')->whereIn('permission_code', $codes)->pluck('id');
    foreach ($actionIds as $actionId) {
        DB::table('admin_role_menu_actions')->insert([
            'role_id' => $roleId,
            'menu_action_id' => (int) $actionId,
        ]);
    }

    $siteId = (int) $agent->admin_site_id;
    DB::table('admin_user_site_roles')->insert([
        'admin_user_id' => $admin->id,
        'site_id' => $siteId,
        '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,
    ]);

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