<?php

use App\Models\AdminRole;
use App\Models\AdminUser;
use App\Models\Draw;
use App\Lottery\DrawStatus;
use App\Support\AdminAuthProfile;
use App\Support\AdminPermissionBridge;
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);
});

function drawViewOnlyToken(): string
{
    $admin = AdminUser::query()->create([
        'username' => 'draw_view_only_admin',
        'name' => 'Draw View',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);

    $role = AdminRole::query()->create([
        'slug' => 'draw_view_only_role',
        'name' => 'Draw view only role',
    ]);
    $role->syncLegacyPermissionSlugs(['prd.draw_result.view']);

    $siteId = AdminUser::defaultAdminSiteId();
    $admin->roles()->sync([
        (int) $role->id => ['site_id' => $siteId, 'granted_at' => now()],
    ]);

    return $admin->fresh()->createToken('test', ['*'], now()->addDay())->plainTextToken;
}

function drawViewOnlyFixtureDraw(): Draw
{
    return Draw::query()->create([
        'draw_no' => '20260604-099',
        'business_date' => '2026-06-04',
        'sequence_no' => 99,
        'status' => DrawStatus::Settled->value,
        'start_time' => now()->subHours(3),
        'close_time' => now()->subHours(2),
        'draw_time' => now()->subHours(1),
        'result_source' => 'rng',
        'current_result_version' => 1,
        'settle_version' => 1,
        'is_reopened' => false,
    ]);
}

test('partial draw review codes do not infer manage slug', function (): void {
    $granted = AdminPermissionBridge::legacySlugsGrantedByMenuActionCodes(['draw.review.publish']);

    expect($granted)->not->toContain('prd.draw_result.manage');
});

test('draw view only admin profile excludes manage and cannot store draw', function (): void {
    $admin = AdminUser::query()->create([
        'username' => 'draw_view_only_profile',
        'name' => 'Draw View',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);

    $role = AdminRole::query()->create([
        'slug' => 'draw_view_only_role_profile',
        'name' => 'Draw view only role',
    ]);
    $role->syncLegacyPermissionSlugs(['prd.draw_result.view']);

    $siteId = AdminUser::defaultAdminSiteId();
    $admin->roles()->sync([
        (int) $role->id => ['site_id' => $siteId, 'granted_at' => now()],
    ]);

    $profile = AdminAuthProfile::fromAdmin($admin->fresh());

    expect($profile['permissions'])->toContain('prd.draw_result.view')
        ->not->toContain('prd.draw_result.manage');

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

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->postJson('/api/v1/admin/draws', [
            'admin_site_id' => $siteId,
            'draw_no' => 'test-view-only-001',
            'start_time' => now()->toIso8601String(),
            'close_time' => now()->addHour()->toIso8601String(),
            'draw_time' => now()->addHours(2)->toIso8601String(),
        ])
        ->assertForbidden();
});

test('draw view only list and show omit finance and operational fields', function (): void {
    $token = drawViewOnlyToken();

    $draw = drawViewOnlyFixtureDraw();

    $listPayload = $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/draws')
        ->assertOk()
        ->json('data');

    $listRow = collect($listPayload['items'])->firstWhere('id', $draw->id);

    expect($listRow)->not->toBeNull()
        ->and($listRow)->not->toHaveKey('total_bet_minor')
        ->and($listRow)->not->toHaveKey('result_source')
        ->and($listPayload['capabilities']['can_manage_draw_results'])->toBeFalse()
        ->and($listPayload['capabilities']['can_view_draw_finance'])->toBeFalse();

    $show = $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/draws/'.$draw->id)
        ->assertOk()
        ->json('data');

    expect($show)->not->toHaveKeys([
        'result_source',
        'current_result_version',
        'settle_version',
        'is_reopened',
        'created_at',
        'updated_at',
    ])
        ->and($show['result_batch_counts'])->not->toHaveKey('pending_review')
        ->and($show['result_batch_counts'])->not->toHaveKey('total')
        ->and($show['capabilities']['can_manage_draw_results'])->toBeFalse();
});

test('draw view only cannot read finance summary and result batches hide ops metadata', function (): void {
    $token = drawViewOnlyToken();
    $draw = drawViewOnlyFixtureDraw();

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/draws/'.$draw->id.'/finance-summary')
        ->assertForbidden();

    $payload = $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/draws/'.$draw->id.'/result-batches')
        ->assertOk()
        ->json('data');

    expect($payload['capabilities']['can_manage_draw_results'])->toBeFalse();

    foreach ($payload['batches'] as $batch) {
        expect($batch)->not->toHaveKeys([
            'source_type',
            'rng_seed_hash',
            'created_by',
            'confirmed_by',
            'created_at',
            'updated_at',
        ]);
    }

    $hasPending = DB::table('draw_result_batches')
        ->where('draw_id', $draw->id)
        ->where('status', 'pending_review')
        ->exists();

    if ($hasPending) {
        $statuses = collect($payload['batches'])->pluck('status')->unique()->all();
        expect($statuses)->not->toContain('pending_review');
    }
});
