<?php

use Tests\TestCase;
use App\Models\AdminUser;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Foundation\Testing\RefreshDatabase;

/*
|--------------------------------------------------------------------------
| Test Case
|--------------------------------------------------------------------------
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
| need to change it using the "pest()" function to bind different classes or traits.
|
*/

pest()->extend(TestCase::class)
 // ->use(RefreshDatabase::class)
    ->in('Feature');

pest()->extend(TestCase::class)->in('Unit');

/*
|--------------------------------------------------------------------------
| Expectations
|--------------------------------------------------------------------------
|
| When you're writing tests, you often need to check that values meet certain conditions. The
| "expect()" function gives you access to a set of "expectations" methods that you can use
| to assert different things. Of course, you may extend the Expectation API at any time.
|
*/

expect()->extend('toBeOne', function () {
    return $this->toBe(1);
});

/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
| project that you don't want to repeat in every file. Here you can also expose helpers as
| global functions to help you to reduce the number of lines of code in your test files.
|
*/

/** 为后台测试账号挂上唯一超级管理员（不绑定站点）。 */
function grantSuperAdminRole(AdminUser $admin): void
{
    \App\Support\PlatformSystemRoles::ensureSuperAdminRole();
    \App\Support\SuperAdminAccount::assign($admin);
}

/** 为后台测试账号挂上代理节点（需已存在 agent_nodes / admin_user_agents 表）。 */
/** Feature 测直调 {@see AgentNodeService::createChild()} 时使用的密码。 */
function agentNodeTestPassword(): string
{
    return '12345678';
}

/** @param  array<string, mixed>  $overrides
 * @return array<string, mixed>
 */
function agentChildPayload(array $overrides = []): array
{
    return array_merge([
        'password' => agentNodeTestPassword(),
        'can_create_child_agent' => true,
        'can_create_player' => true,
    ], $overrides);
}

function bindAdminUserToAgent(AdminUser $admin, int $agentNodeId): void
{
    DB::table('admin_user_agents')->updateOrInsert(
        ['admin_user_id' => $admin->id],
        [
            'agent_node_id' => $agentNodeId,
            'is_primary' => true,
            'granted_at' => now(),
        ],
    );
}

/** 确保默认站点一级代理已有占成/授信档案（子代理创建与额度校验依赖）。 */
function ensureRootAgentProfileSeeded(): void
{
    $rootId = DB::table('agent_nodes')->where('depth', 0)->value('id');
    if ($rootId === null) {
        return;
    }

    \App\Models\AgentProfile::query()->updateOrCreate(
        ['agent_node_id' => (int) $rootId],
        [
            'total_share_rate' => 100,
            'credit_limit' => 1_000_000,
            'allocated_credit' => 0,
            'used_credit' => 0,
            'rebate_limit' => 1,
            'default_player_rebate' => 0,
        ],
    );
}

function ensureAdminActionCatalogSeeded(): void
{
    if (! Schema::hasTable('admin_action_catalog')) {
        Schema::create('admin_action_catalog', static function ($table): void {
            $table->id();
            $table->string('code')->unique();
            $table->string('name');
            $table->unsignedTinyInteger('status')->default(1);
            $table->timestamps();
        });
    }

    $now = Carbon::now();
    foreach ([
        ['code' => 'view', 'name' => '查看'],
        ['code' => 'manage', 'name' => '管理'],
    ] as $row) {
        DB::table('admin_action_catalog')->updateOrInsert(
            ['code' => $row['code']],
            [
                'name' => $row['name'],
                'status' => 1,
                'created_at' => $now,
                'updated_at' => $now,
            ],
        );
    }
}

/**
 * 返回项目内所有 Broadcast 事件类列表，供 Event::fake() 拦截广播使用。
 *
 * 业务切到 reverb driver 后，fake 列表不全会导致未拦截的 broadcast 真实派发、
 * 真实连接 Reverb/Pusher，CI 环境无可用 server 时直接 500。本 helper 保证：
 *   Event::fake(allBroadcastEvents())
 * 一行覆盖流程中可能触发的所有事件。
 *
 * 不可使用 Event::fake() 无参形式：会同时拦截 Illuminate\Database\Events\* 等框架事件，
 * 干扰 RefreshDatabase / model events / 自定义 boot hooks。
 *
 * @return list<class-string>
 */
function allBroadcastEvents(): array
{
    return [
        \App\Events\BalanceUpdateBroadcast::class,
        \App\Events\DrawCountdownBroadcast::class,
        \App\Events\DrawResultPublishedBroadcast::class,
        \App\Events\DrawStatusChangeBroadcast::class,
        \App\Events\JackpotBurstBroadcast::class,
        \App\Events\OddsUpdateBroadcast::class,
        \App\Events\PlayCatalogUpdatedBroadcast::class,
        \App\Events\PlayToggleBroadcast::class,
        \App\Events\RiskSoldOutBroadcast::class,
        \App\Events\RiskWarningBroadcast::class,
    ];
}
