<?php

use App\Models\Draw;
use App\Models\Player;
use App\Models\AdminRole;
use App\Models\AdminUser;
use App\Models\AuditLog;
use App\Models\WalletTxn;
use App\Models\TicketItem;
use App\Models\TicketOrder;
use App\Models\DrawResultBatch;
use App\Models\PlayerWallet;
use App\Models\SettlementBatch;
use App\Models\TicketSettlementDetail;
use App\Lottery\DrawStatus;
use Illuminate\Support\Facades\Hash;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

function settlementPayoutManagerToken(): string
{
    $admin = AdminUser::query()->create([
        'username' => 'settlement_manager',
        'name' => 'Settlement Manager',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);

    $role = AdminRole::query()->create([
        'slug' => 'settlement_manager_role',
        'name' => 'Settlement Manager Role',
    ]);
    $role->syncLegacyPermissionSlugs(['prd.payout.manage']);

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

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

test('admin can apply settlement payout adjustment for paid batch and audit it', function (): void {
    $token = settlementPayoutManagerToken();
    $managerId = (int) AdminUser::query()->where('username', 'settlement_manager')->value('id');

    $draw = Draw::query()->create([
        'draw_no' => '20260603-001',
        'business_date' => '2026-06-03',
        'sequence_no' => 1,
        'status' => DrawStatus::Settled->value,
        'start_time' => now()->subHour(),
        'close_time' => now()->subMinutes(30),
        'draw_time' => now()->subMinutes(20),
        'cooling_end_time' => now()->subMinutes(10),
        'result_source' => 'manual',
        'current_result_version' => 1,
        'settle_version' => 1,
        'is_reopened' => false,
    ]);

    $player = Player::query()->create([
        'site_code' => 'main',
        'site_player_id' => 'settlement-adjust-player',
        'username' => 'settle_player',
        'nickname' => null,
        'default_currency' => 'NPR',
        'status' => 0,
    ]);

    $wallet = PlayerWallet::query()->create([
        'player_id' => $player->id,
        'wallet_type' => 'lottery',
        'currency_code' => 'NPR',
        'balance' => 1_000,
        'frozen_balance' => 0,
        'status' => 0,
        'version' => 0,
    ]);

    $order = TicketOrder::query()->create([
        'order_no' => 'TO-SETTLE-ADJUST-1',
        'player_id' => $player->id,
        'draw_id' => $draw->id,
        'currency_code' => 'NPR',
        'total_bet_amount' => 100,
        'total_rebate_amount' => 0,
        'total_actual_deduct' => 100,
        'total_estimated_payout' => 500,
        'status' => 'settled',
        'submit_source' => 'h5',
        'client_trace_id' => 'settlement-adjust-trace',
    ]);

    $item = TicketItem::query()->create([
        'ticket_no' => 'TK-SETTLE-ADJUST-1',
        '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' => 'straight',
        'unit_bet_amount' => 100,
        'total_bet_amount' => 100,
        'rebate_rate_snapshot' => 0,
        'commission_rate_snapshot' => 0,
        'actual_deduct_amount' => 100,
        'odds_snapshot_json' => [],
        'rule_snapshot_json' => [],
        'combination_count' => 1,
        'estimated_max_payout' => 500,
        'risk_locked_amount' => 0,
        'status' => 'settled_win',
        'fail_reason_code' => null,
        'fail_reason_text' => null,
        'win_amount' => 500,
        'jackpot_win_amount' => 0,
        'settled_at' => now()->subMinutes(5),
    ]);

    $resultBatch = DrawResultBatch::query()->create([
        'draw_id' => $draw->id,
        'result_version' => 1,
        'source_type' => 'manual',
        'rng_seed_hash' => null,
        'raw_seed_encrypted' => null,
        'status' => 'published',
        'created_by' => $managerId,
        'confirmed_by' => $managerId,
        'confirmed_at' => now()->subMinutes(9),
    ]);

    $batch = SettlementBatch::query()->create([
        'draw_id' => $draw->id,
        'result_batch_id' => $resultBatch->id,
        'settle_version' => 1,
        'status' => 'paid',
        'total_ticket_count' => 1,
        'total_win_count' => 1,
        'total_payout_amount' => 500,
        'total_jackpot_payout_amount' => 0,
        'review_status' => 'approved',
        'reviewed_by' => $managerId,
        'reviewed_at' => now()->subMinutes(6),
        'review_remark' => 'approved',
        'paid_at' => now()->subMinutes(5),
        'started_at' => now()->subMinutes(8),
        'finished_at' => now()->subMinutes(7),
    ]);

    TicketSettlementDetail::query()->create([
        'settlement_batch_id' => $batch->id,
        'ticket_item_id' => $item->id,
        'matched_prize_tier' => '1st',
        'win_amount' => 500,
        'jackpot_allocation_amount' => 0,
        'match_detail_json' => ['numbers' => ['1234']],
    ]);

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->postJson("/api/v1/admin/settlement-batches/{$batch->id}/adjustments", [
            'player_id' => $player->id,
            'amount_delta' => 120,
            'reason' => 'manual payout correction',
        ])
        ->assertOk()
        ->assertJsonPath('data.batch_id', $batch->id)
        ->assertJsonPath('data.player_id', $player->id)
        ->assertJsonPath('data.amount_delta', 120)
        ->assertJsonPath('data.direction', 'credit');

    $wallet->refresh();
    expect((int) $wallet->balance)->toBe(1_120)
        ->and(WalletTxn::query()->where('biz_type', 'settlement_adjustment')->count())->toBe(1)
        ->and(AuditLog::query()->where('module_code', 'settlement')->where('action_code', 'payout_adjustment')->count())->toBe(1);
});

test('admin settlement payout adjustment rejects player outside batch', function (): void {
    $token = settlementPayoutManagerToken();
    $managerId = (int) AdminUser::query()->where('username', 'settlement_manager')->value('id');

    $draw = Draw::query()->create([
        'draw_no' => '20260603-002',
        'business_date' => '2026-06-03',
        'sequence_no' => 2,
        'status' => DrawStatus::Settled->value,
        'start_time' => now()->subHour(),
        'close_time' => now()->subMinutes(30),
        'draw_time' => now()->subMinutes(20),
        'cooling_end_time' => now()->subMinutes(10),
        'result_source' => 'manual',
        'current_result_version' => 1,
        'settle_version' => 1,
        'is_reopened' => false,
    ]);

    $resultBatch = DrawResultBatch::query()->create([
        'draw_id' => $draw->id,
        'result_version' => 1,
        'source_type' => 'manual',
        'rng_seed_hash' => null,
        'raw_seed_encrypted' => null,
        'status' => 'published',
        'created_by' => $managerId,
        'confirmed_by' => $managerId,
        'confirmed_at' => now()->subMinutes(9),
    ]);

    $batch = SettlementBatch::query()->create([
        'draw_id' => $draw->id,
        'result_batch_id' => $resultBatch->id,
        'settle_version' => 1,
        'status' => 'paid',
        'total_ticket_count' => 0,
        'total_win_count' => 0,
        'total_payout_amount' => 0,
        'total_jackpot_payout_amount' => 0,
        'review_status' => 'approved',
        'reviewed_by' => $managerId,
        'reviewed_at' => now()->subMinutes(6),
        'review_remark' => 'approved',
        'paid_at' => now()->subMinutes(5),
        'started_at' => now()->subMinutes(8),
        'finished_at' => now()->subMinutes(7),
    ]);

    $player = Player::query()->create([
        'site_code' => 'main',
        'site_player_id' => 'not-in-batch',
        'username' => null,
        'nickname' => null,
        'default_currency' => 'NPR',
        'status' => 0,
    ]);

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->postJson("/api/v1/admin/settlement-batches/{$batch->id}/adjustments", [
            'player_id' => $player->id,
            'amount_delta' => 80,
            'reason' => 'should reject',
        ])
        ->assertStatus(422);

    expect(WalletTxn::query()->where('biz_type', 'settlement_adjustment')->count())->toBe(0);
});
