<?php

use App\Models\AdminUser;
use App\Lottery\ErrorCode;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('admin ping requires authentication', function () {
    $this->getJson('/api/v1/admin/ping')->assertUnauthorized()
        ->assertJsonPath('code', ErrorCode::AdminUnauthenticated->value);
});

test('admin auth me returns current admin profile', function () {
    $this->artisan('lottery:admin-auth-sync')->assertExitCode(0);

    $admin = AdminUser::query()->create([
        'username' => 'admin_me',
        'name' => '管理员本人',
        'email' => null,
        'password' => 'secret-strong',
        'status' => 0,
        'is_super_admin' => true,
    ]);

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

    $resp = $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/auth/me')
        ->assertOk()
        ->assertJsonPath('code', ErrorCode::Success->value)
        ->assertJsonPath('data.admin.username', 'admin_me')
        ->assertJsonPath('data.admin.account_kind', 'super_admin')
        ->assertJsonPath('data.admin.navigation.0.segment', 'dashboard')
        ->assertJsonStructure(['data' => ['admin' => ['permissions', 'operational_permissions']]]);

    $permissions = $resp->json('data.admin.permissions');
    $operational = $resp->json('data.admin.operational_permissions');
    expect($permissions)->toBeArray()->not->toBeEmpty()
        ->and($operational)->toBeArray()->not->toBeEmpty()
        ->and($permissions[0])->toStartWith('prd.')
        ->and($operational[0])->not->toStartWith('prd.');
});

test('admin login returns bearer token when captcha passes validation', function () {
    $admin = AdminUser::query()->create([
        'username' => 'tester',
        'name' => '测试昵称',
        'email' => null,
        'password' => 'secret-strong',
        'status' => 0,
    ]);
    // 登录返回的 navigation 需要管理员权限（避免测试依赖默认 DB 状态）
    grantSuperAdminRole($admin);

    $captchaKey = (string) Str::uuid();
    Cache::put(
        'admin_captcha:'.$captchaKey,
        hash_hmac('sha256', 'xwz2', (string) config('app.key')),
        now()->addSeconds(120),
    );

    $resp = $this->postJson('/api/v1/admin/auth/login', [
        'account' => 'Tester',
        'password' => 'secret-strong',
        'captcha_key' => $captchaKey,
        'captcha_code' => 'xwz2',
    ]);

    $resp->assertOk()
        ->assertJsonPath('code', ErrorCode::Success->value)
        ->assertJsonPath('data.admin.username', 'tester')
        ->assertJsonPath('data.admin.nickname', '测试昵称')
        ->assertJsonPath('data.admin.navigation.0.segment', 'dashboard')
        ->assertJsonPath('data.admin.navigation.0.href', '/admin')
        ->assertJsonPath('data.admin.navigation.0.nav_group', 'overview')
        ->assertJsonPath('data.admin.navigation.1.segment', 'agents')
        ->assertJsonPath('data.admin.navigation.1.nav_group', 'agent')
        ->assertJsonPath('data.admin.navigation.2.segment', 'settlement_center')
        ->assertJsonStructure(['data' => ['token', 'token_type', 'admin' => ['id', 'username', 'nickname', 'email', 'permissions', 'operational_permissions', 'navigation']]]);

    $token = $resp->json('data.token');
    expect($token)->not->toBeNull();

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/ping')
        ->assertOk()
        ->assertJsonPath('data.scope', 'admin');
});

test('agent operator auth me omits platform-only navigation', function (): void {
    $this->artisan('lottery:admin-auth-sync')->assertExitCode(0);

    $siteId = (int) DB::table('admin_sites')->where('is_default', true)->value('id');
    $rootId = (int) DB::table('agent_nodes')->where('admin_site_id', $siteId)->where('depth', 0)->value('id');

    $admin = AdminUser::query()->create([
        'username' => 'agent_nav_ops',
        'name' => 'Agent Nav',
        'email' => null,
        'password' => 'secret-strong',
        'status' => 0,
    ]);

    $now = now();
    $roleId = DB::table('admin_roles')->insertGetId([
        'slug' => 'agent_nav_ops_role',
        'code' => 'agent_nav_ops_role',
        'name' => 'Agent Nav Ops',
        'description' => null,
        'status' => 1,
        'is_system' => false,
        'sort_order' => 0,
        'created_at' => $now,
        'updated_at' => $now,
    ]);

    $codes = ['agent.node.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,
        ]);
    }

    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' => $rootId,
        'is_primary' => true,
        'granted_at' => $now,
    ]);

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

    $segments = $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/auth/me')
        ->assertOk()
        ->json('data.admin.navigation');

    $keys = array_column($segments, 'segment');
    expect($keys)->toContain('agents', 'reports')
        ->and($keys)->not->toContain('admin_users', 'admin_roles', 'settings', 'integration', 'rules_plays');
});

test('admin captcha exposes key and image base64', function () {
    $resp = $this->getJson('/api/v1/admin/auth/captcha');

    $resp->assertOk()
        ->assertJsonPath('code', ErrorCode::Success->value);

    $data = $resp->json('data');
    expect($data)->toBeArray()
        ->and(Str::isUuid((string) $data['captcha_key']))->toBeTrue()
        ->and((string) $data['image_base64'])->not->toBe('');
});

test('login rejects wrong password with masked message', function () {
    AdminUser::query()->create([
        'username' => 'bad_tester',
        'name' => 'X',
        'email' => null,
        'password' => 'right-only',
        'status' => 0,
    ]);

    $captchaKey = (string) Str::uuid();
    Cache::put(
        'admin_captcha:'.$captchaKey,
        hash_hmac('sha256', 'aaaa', (string) config('app.key')),
        now()->addSeconds(120),
    );

    $this->postJson('/api/v1/admin/auth/login', [
        'account' => 'bad_tester',
        'password' => 'wrong-password',
        'captcha_key' => $captchaKey,
        'captcha_code' => 'aaaa',
    ])->assertUnauthorized()
        ->assertJsonPath('code', ErrorCode::AdminCredentialsInvalid->value);
});
