<?php

use App\Models\Draw;
use App\Models\Player;
use App\Models\AdminUser;
use App\Lottery\DrawStatus;
use App\Support\PlayerFundingMode;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('credit ledger biz_type payment_record excludes credit rows', function (): void {
    $site = DB::table('admin_sites')->where('is_default', true)->first();
    $siteId = (int) $site->id;
    $siteCode = (string) $site->code;

    $periodId = (int) DB::table('settlement_periods')->insertGetId([
        'admin_site_id' => $siteId,
        'period_start' => now()->subDay(),
        'period_end' => now()->addDay(),
        'status' => 'closed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $player = Player::query()->create([
        'site_code' => $siteCode,
        'site_player_id' => 'native:ledger-filter',
        'funding_mode' => PlayerFundingMode::CREDIT,
        'username' => 'ledger_filter_user',
        'default_currency' => 'NPR',
        'status' => 0,
    ]);

    DB::table('credit_ledger')->insert([
        'owner_type' => 'player',
        'owner_id' => $player->id,
        'amount' => -100,
        'reason' => 'bet_hold',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $billId = (int) DB::table('settlement_bills')->insertGetId([
        'settlement_period_id' => $periodId,
        'bill_type' => 'player',
        'owner_type' => 'player',
        'owner_id' => $player->id,
        'counterparty_type' => 'agent',
        'counterparty_id' => 1,
        'net_amount' => 100,
        'unpaid_amount' => 0,
        'paid_amount' => 100,
        'status' => 'settled',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $paymentId = (int) DB::table('payment_records')->insertGetId([
        'settlement_bill_id' => $billId,
        'payer_type' => 'player',
        'payer_id' => $player->id,
        'payee_type' => 'agent',
        'payee_id' => 1,
        'amount' => 100,
        'status' => 'confirmed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $admin = AdminUser::query()->create([
        'username' => 'ledger_filter_super',
        'name' => 'Ledger Filter',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($admin);
    $token = $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/credit-ledger?admin_site_id='.$siteId.'&settlement_period_id='.$periodId.'&reason=payment_record')
        ->assertOk()
        ->assertJsonPath('data.total', 1)
        ->assertJsonPath('data.items.0.entry_kind', 'payment')
        ->assertJsonPath('data.items.0.id', $paymentId);

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/credit-ledger?admin_site_id='.$siteId.'&settlement_period_id='.$periodId.'&txn_no=CL')
        ->assertOk()
        ->assertJsonPath('data.total', 1)
        ->assertJsonPath('data.items.0.entry_kind', 'credit');
});

test('credit ledger index includes payment on agent bill', function (): void {
    $site = DB::table('admin_sites')->where('is_default', true)->first();
    $siteId = (int) $site->id;
    $agentId = (int) DB::table('agent_nodes')->where('admin_site_id', $siteId)->where('depth', 0)->value('id');

    $periodId = (int) DB::table('settlement_periods')->insertGetId([
        'admin_site_id' => $siteId,
        'period_start' => now()->subDay(),
        'period_end' => now()->addDay(),
        'status' => 'closed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $billId = (int) DB::table('settlement_bills')->insertGetId([
        'settlement_period_id' => $periodId,
        'bill_type' => 'agent',
        'owner_type' => 'agent',
        'owner_id' => $agentId,
        'counterparty_type' => 'platform',
        'counterparty_id' => 0,
        'net_amount' => 3000,
        'unpaid_amount' => 0,
        'paid_amount' => 3000,
        'status' => 'settled',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $paymentId = (int) DB::table('payment_records')->insertGetId([
        'settlement_bill_id' => $billId,
        'payer_type' => 'agent',
        'payer_id' => $agentId,
        'payee_type' => 'platform',
        'payee_id' => 0,
        'amount' => 3000,
        'status' => 'confirmed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $admin = AdminUser::query()->create([
        'username' => 'ledger_agent_bill_super',
        'name' => 'Agent Bill Ledger',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($admin);
    $token = $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/credit-ledger?admin_site_id='.$siteId.'&settlement_period_id='.$periodId.'&reason=payment_record')
        ->assertOk()
        ->assertJsonPath('data.total', 1)
        ->assertJsonPath('data.items.0.entry_kind', 'payment')
        ->assertJsonPath('data.items.0.id', $paymentId)
        ->assertJsonPath('data.items.0.bill_type', 'agent');
});

test('credit ledger settlement bill reference keeps the referenced bill id', function (): void {
    $site = DB::table('admin_sites')->where('is_default', true)->first();
    $siteId = (int) $site->id;
    $siteCode = (string) $site->code;

    $periodId = (int) DB::table('settlement_periods')->insertGetId([
        'admin_site_id' => $siteId,
        'period_start' => now()->subDay(),
        'period_end' => now()->addDay(),
        'status' => 'closed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $player = Player::query()->create([
        'site_code' => $siteCode,
        'site_player_id' => 'native:bill-ref-ledger',
        'funding_mode' => PlayerFundingMode::CREDIT,
        'username' => 'bill_ref_ledger_user',
        'default_currency' => 'NPR',
        'status' => 0,
    ]);

    $referencedBillId = (int) DB::table('settlement_bills')->insertGetId([
        'settlement_period_id' => $periodId,
        'bill_type' => 'player',
        'owner_type' => 'player',
        'owner_id' => $player->id,
        'counterparty_type' => 'agent',
        'counterparty_id' => 1,
        'net_amount' => -100,
        'unpaid_amount' => 0,
        'paid_amount' => 100,
        'status' => 'settled',
        'created_at' => now()->subMinute(),
        'updated_at' => now()->subMinute(),
    ]);

    $newerBillId = (int) DB::table('settlement_bills')->insertGetId([
        'settlement_period_id' => $periodId,
        'bill_type' => 'player',
        'owner_type' => 'player',
        'owner_id' => $player->id,
        'counterparty_type' => 'agent',
        'counterparty_id' => 1,
        'net_amount' => -200,
        'unpaid_amount' => 0,
        'paid_amount' => 200,
        'status' => 'settled',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    DB::table('credit_ledger')->insert([
        'owner_type' => 'player',
        'owner_id' => $player->id,
        'amount' => 100,
        'reason' => 'settlement_payout',
        'ref_type' => 'settlement_bill',
        'ref_id' => $referencedBillId,
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $admin = AdminUser::query()->create([
        'username' => 'ledger_bill_ref_super',
        'name' => 'Ledger Bill Ref',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($admin);
    $token = $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/credit-ledger?admin_site_id='.$siteId.'&settlement_period_id='.$periodId.'&reason=settlement_payout')
        ->assertOk()
        ->assertJsonPath('data.total', 1)
        ->assertJsonPath('data.items.0.entry_kind', 'credit')
        ->assertJsonPath('data.items.0.settlement_bill_id', $referencedBillId)
        ->assertJsonPath('data.items.0.ref_id', $referencedBillId);
});

test('credit ledger settled bill payment row omits adjustment actions', function (): void {
    $site = DB::table('admin_sites')->where('is_default', true)->first();
    $siteId = (int) $site->id;
    $siteCode = (string) $site->code;

    $periodId = (int) DB::table('settlement_periods')->insertGetId([
        'admin_site_id' => $siteId,
        'period_start' => now()->subDay(),
        'period_end' => now()->addDay(),
        'status' => 'closed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $player = Player::query()->create([
        'site_code' => $siteCode,
        'site_player_id' => 'native:ledger-settled-actions',
        'funding_mode' => PlayerFundingMode::CREDIT,
        'username' => 'ledger_settled_actions',
        'default_currency' => 'NPR',
        'status' => 0,
    ]);

    $billId = (int) DB::table('settlement_bills')->insertGetId([
        'settlement_period_id' => $periodId,
        'bill_type' => 'player',
        'owner_type' => 'player',
        'owner_id' => $player->id,
        'counterparty_type' => 'agent',
        'counterparty_id' => 1,
        'net_amount' => 100,
        'unpaid_amount' => 0,
        'paid_amount' => 100,
        'status' => 'settled',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    DB::table('payment_records')->insert([
        'settlement_bill_id' => $billId,
        'payer_type' => 'player',
        'payer_id' => $player->id,
        'payee_type' => 'agent',
        'payee_id' => 1,
        'amount' => 100,
        'status' => 'confirmed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $admin = AdminUser::query()->create([
        'username' => 'ledger_settled_actions_super',
        'name' => 'Ledger Settled Actions',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($admin);
    $token = $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/credit-ledger?admin_site_id='.$siteId.'&settlement_period_id='.$periodId.'&reason=payment_record')
        ->assertOk()
        ->assertJsonPath('data.items.0.available_actions', ['view_player', 'view_bill']);
});

test('credit ledger actionable_only paginates after hydration filter', function (): void {
    $site = DB::table('admin_sites')->where('is_default', true)->first();
    $siteId = (int) $site->id;
    $siteCode = (string) $site->code;
    $agentId = (int) DB::table('agent_nodes')->where('admin_site_id', $siteId)->where('depth', 0)->value('id');

    $periodId = (int) DB::table('settlement_periods')->insertGetId([
        'admin_site_id' => $siteId,
        'period_start' => now()->subDay(),
        'period_end' => now()->addDay(),
        'status' => 'closed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $player = Player::query()->create([
        'site_code' => $siteCode,
        'site_player_id' => 'native:ledger-actionable',
        'funding_mode' => PlayerFundingMode::CREDIT,
        'username' => 'ledger_actionable_user',
        'default_currency' => 'NPR',
        'status' => 0,
    ]);

    DB::table('credit_ledger')->insert([
        'owner_type' => 'player',
        'owner_id' => $player->id,
        'amount' => -100,
        'reason' => 'bet_hold',
        'created_at' => now()->subMinute(),
        'updated_at' => now()->subMinute(),
    ]);

    $actionableBillId = (int) DB::table('settlement_bills')->insertGetId([
        'settlement_period_id' => $periodId,
        'bill_type' => 'player',
        'owner_type' => 'player',
        'owner_id' => $player->id,
        'counterparty_type' => 'agent',
        'counterparty_id' => $agentId,
        'net_amount' => 200,
        'unpaid_amount' => 200,
        'paid_amount' => 0,
        'status' => 'confirmed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $actionablePaymentId = (int) DB::table('payment_records')->insertGetId([
        'settlement_bill_id' => $actionableBillId,
        'payer_type' => 'player',
        'payer_id' => $player->id,
        'payee_type' => 'agent',
        'payee_id' => $agentId,
        'amount' => 50,
        'status' => 'confirmed',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $admin = AdminUser::query()->create([
        'username' => 'ledger_actionable_super',
        'name' => 'Ledger Actionable',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($admin);
    $token = $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/credit-ledger?admin_site_id='.$siteId.'&settlement_period_id='.$periodId.'&actionable_only=1')
        ->assertOk()
        ->assertJsonPath('data.total', 1)
        ->assertJsonPath('data.items.0.entry_kind', 'payment')
        ->assertJsonPath('data.items.0.id', $actionablePaymentId);

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/credit-ledger?admin_site_id='.$siteId.'&settlement_period_id='.$periodId.'&actionable_only=1&per_page=1&page=2')
        ->assertOk()
        ->assertJsonPath('data.total', 1)
        ->assertJsonPath('data.items', []);
});

test('credit ledger entry_kind share returns share ledger rows', function (): void {
    $site = DB::table('admin_sites')->where('is_default', true)->first();
    $siteId = (int) $site->id;
    $siteCode = (string) $site->code;
    $rootId = (int) DB::table('agent_nodes')->where('admin_site_id', $siteId)->where('depth', 0)->value('id');

    $periodId = (int) DB::table('settlement_periods')->insertGetId([
        'admin_site_id' => $siteId,
        'period_start' => now()->subDay(),
        'period_end' => now()->addDay(),
        'status' => 'open',
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $player = Player::query()->create([
        'site_code' => $siteCode,
        'site_player_id' => 'native:share-ledger',
        'funding_mode' => PlayerFundingMode::CREDIT,
        'username' => 'share_ledger_user',
        'default_currency' => 'NPR',
        'status' => 0,
        'agent_node_id' => $rootId,
    ]);

    $settledAt = now()->toDateTimeString();
    $shareId = (int) DB::table('share_ledger')->insertGetId([
        'ticket_item_id' => createShareLedgerTicketItem($player),
        'player_id' => $player->id,
        'agent_node_id' => $rootId,
        'agent_path' => json_encode([$rootId]),
        'share_snapshot' => json_encode([
            'total_shares' => ['ROOT' => 1.0],
            'chain_codes' => ['ROOT'],
        ]),
        'game_win_loss' => 1200,
        'basic_rebate' => 0,
        'shared_net_win_loss' => 1200,
        'allocations_json' => json_encode([]),
        'settled_at' => $settledAt,
        'created_at' => $settledAt,
        'updated_at' => $settledAt,
    ]);

    $admin = AdminUser::query()->create([
        'username' => 'share_ledger_super',
        'name' => 'Share Ledger',
        'email' => null,
        'password' => Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($admin);
    $token = $admin->createToken('test', ['*'], now()->addDay())->plainTextToken;

    $this->withHeader('Authorization', 'Bearer '.$token)
        ->getJson('/api/v1/admin/credit-ledger?admin_site_id='.$siteId.'&settlement_period_id='.$periodId.'&entry_kind=share')
        ->assertOk()
        ->assertJsonPath('data.total', 1)
        ->assertJsonPath('data.items.0.entry_kind', 'share')
        ->assertJsonPath('data.items.0.id', $shareId)
        ->assertJsonPath('data.items.0.biz_type', 'share_ledger')
        ->assertJsonPath('data.items.0.signed_amount', 1200);
});

function createShareLedgerTicketItem(Player $player): int
{
    $draw = Draw::query()->create([
        'draw_no' => 'DRAW-SHARE-LEDGER',
        'business_date' => now()->toDateString(),
        'sequence_no' => random_int(1, 9999),
        'status' => DrawStatus::Open->value,
        'current_result_version' => 0,
        'settle_version' => 0,
        'is_reopened' => false,
    ]);

    $orderId = (int) DB::table('ticket_orders')->insertGetId([
        'order_no' => 'ORD-SHARE-LEDGER',
        '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' => 'confirmed',
        'submit_source' => 'h5',
        'client_trace_id' => null,
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    return (int) DB::table('ticket_items')->insertGetId([
        'ticket_no' => 'T-SHARE-LEDGER',
        'order_id' => $orderId,
        'player_id' => $player->id,
        'draw_id' => $draw->id,
        'normalized_number' => '1234',
        'play_code' => 'big',
        'dimension' => 2,
        'unit_bet_amount' => 1000,
        'total_bet_amount' => 1000,
        'rebate_rate_snapshot' => 0,
        'commission_rate_snapshot' => 0,
        'actual_deduct_amount' => 1000,
        'combination_count' => 1,
        'estimated_max_payout' => 0,
        'risk_locked_amount' => 0,
        'status' => 'settled_lose',
        'win_amount' => 0,
        'jackpot_win_amount' => 0,
        'created_at' => now(),
        'updated_at' => now(),
    ]);
}
