<?php

use App\Models\AgentNode;
use App\Models\AgentProfile;
use App\Models\Player;
use App\Services\Agent\AgentNodeService;
use App\Services\AgentSettlement\AgentSettlementPeriodCloseService;
use App\Support\Settlement\DesignDocExample12;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->artisan('lottery:admin-auth-sync')->assertExitCode(0);
});

test('period close from share ledger matches design doc example 12', function (): void {
    $siteId = (int) DB::table('admin_sites')->where('is_default', true)->value('id');
    $siteCode = (string) DB::table('admin_sites')->where('id', $siteId)->value('code');
    $rootId = (int) DB::table('agent_nodes')->where('admin_site_id', $siteId)->where('depth', 0)->value('id');

    $service = app(AgentNodeService::class);
    $super = \App\Models\AdminUser::query()->create([
        'username' => 'e2e_super',
        'name' => 'E2E',
        'email' => null,
        'password' => \Illuminate\Support\Facades\Hash::make('secret-strong'),
        'status' => 0,
    ]);
    grantSuperAdminRole($super);

    $a = $service->createChild($super, agentChildPayload([
        'parent_id' => $rootId,
        'code' => 'A',
        'name' => 'A',
        'username' => 'e2e_a',
        'total_share_rate' => 60,
        'credit_limit' => 500000,
    ]));
    $b = $service->createChild($super, agentChildPayload([
        'parent_id' => $a->id,
        'code' => 'B',
        'name' => 'B',
        'username' => 'e2e_b',
        'total_share_rate' => 40,
        'credit_limit' => 200000,
    ]));
    $c = $service->createChild($super, agentChildPayload([
        'parent_id' => $b->id,
        'code' => 'C',
        'name' => 'C',
        'username' => 'e2e_c',
        'total_share_rate' => 25,
        'credit_limit' => 100000,
    ]));

    $player = Player::query()->create([
        'site_code' => $siteCode,
        'agent_node_id' => $c->id,
        'site_player_id' => 'e2e-p1',
        'username' => 'e2eplayer',
        'nickname' => null,
        'default_currency' => 'NPR',
        'status' => 0,
    ]);

    $draw = \App\Models\Draw::query()->create([
        'draw_no' => 'E2E-AG-001',
        'business_date' => now()->toDateString(),
        'sequence_no' => 99,
        'status' => \App\Lottery\DrawStatus::Open->value,
        'start_time' => null,
        'close_time' => null,
        'draw_time' => null,
        'cooling_end_time' => null,
        'result_source' => null,
        'current_result_version' => 0,
        'settle_version' => 0,
        'is_reopened' => false,
    ]);

    $orderId = (int) DB::table('ticket_orders')->insertGetId([
        'order_no' => 'ORD-E2E-AG-1',
        'player_id' => $player->id,
        'draw_id' => $draw->id,
        'currency_code' => 'NPR',
        'total_bet_amount' => 10000,
        'total_rebate_amount' => 0,
        'total_actual_deduct' => 10000,
        'total_estimated_payout' => 0,
        'status' => 'confirmed',
        'submit_source' => 'h5',
        'client_trace_id' => null,
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $ticketItemId = (int) DB::table('ticket_items')->insertGetId([
        'ticket_no' => 'T-E2E-AG-1',
        'order_id' => $orderId,
        'player_id' => $player->id,
        'draw_id' => $draw->id,
        'original_number' => null,
        'normalized_number' => '1234',
        'play_code' => 'big',
        'dimension' => 2,
        'digit_slot' => null,
        'bet_mode' => null,
        'unit_bet_amount' => 10000,
        'total_bet_amount' => 10000,
        'rebate_rate_snapshot' => 0,
        'commission_rate_snapshot' => 0,
        'actual_deduct_amount' => 10000,
        'odds_snapshot_json' => null,
        'rule_snapshot_json' => null,
        'combination_count' => 1,
        'estimated_max_payout' => 0,
        'risk_locked_amount' => 0,
        'status' => 'settled_lose',
        'fail_reason_code' => null,
        'fail_reason_text' => null,
        'win_amount' => 0,
        'jackpot_win_amount' => 0,
        'settled_at' => null,
        'created_at' => now(),
        'updated_at' => now(),
    ]);

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

    DB::table('share_ledger')->insert([
        'ticket_item_id' => $ticketItemId,
        'player_id' => $player->id,
        'agent_node_id' => $c->id,
        'agent_path' => json_encode([$a->id, $b->id, $c->id]),
        'share_snapshot' => json_encode([
            'total_shares' => ['C' => 25, 'B' => 40, 'A' => 60],
            'actual_shares' => ['C' => 25, 'B' => 15, 'A' => 20, 'platform' => 40],
            'chain_codes' => ['C', 'B', 'A'],
            'agent_path' => [$a->id, $b->id, $c->id],
        ]),
        'game_win_loss' => DesignDocExample12::GAME_WIN_LOSS,
        'basic_rebate' => DesignDocExample12::BASIC_REBATE,
        'shared_net_win_loss' => DesignDocExample12::SHARED_NET_WIN_LOSS,
        'allocations_json' => json_encode([]),
        'settled_at' => $settledAt,
        'created_at' => $settledAt,
        'updated_at' => $settledAt,
    ]);

    DB::table('rebate_records')->insert([
        [
            'player_id' => $player->id,
            'ticket_item_id' => $ticketItemId,
            'game_type' => '*',
            'valid_bet_amount' => 10000,
            'rebate_rate' => 0.005,
            'rebate_amount' => DesignDocExample12::BASIC_REBATE,
            'rebate_type' => 'basic',
            'owner_agent_id' => $c->id,
            'status' => 'accrued',
            'created_at' => $settledAt,
            'updated_at' => $settledAt,
        ],
        [
            'player_id' => $player->id,
            'ticket_item_id' => $ticketItemId,
            'game_type' => '*',
            'valid_bet_amount' => 10000,
            'rebate_rate' => 0.002,
            'rebate_amount' => DesignDocExample12::EXTRA_REBATE_BY_C,
            'rebate_type' => 'extra',
            'owner_agent_id' => $c->id,
            'status' => 'accrued',
            'created_at' => $settledAt,
            'updated_at' => $settledAt,
        ],
    ]);

    $close = app(AgentSettlementPeriodCloseService::class)->closePeriod($periodId);

    $playerBill = DB::table('settlement_bills')
        ->where('settlement_period_id', $periodId)
        ->where('bill_type', 'player')
        ->where('owner_id', $player->id)
        ->first();

    expect($playerBill)->not->toBeNull();
    expect((int) $playerBill->net_amount)->toBe((int) DesignDocExample12::PLAYER_NET_SETTLEMENT);

    $edgeCtoB = DB::table('settlement_bills')
        ->where('settlement_period_id', $periodId)
        ->where('meta_json', 'like', '%C_to_B%')
        ->value('net_amount');
    expect((int) $edgeCtoB)->toBe((int) round(DesignDocExample12::TIER_C_TO_B));

    expect($close['rebate_dispatched'])->toBe(2);
    expect($close['rebate_allocations'])->toBeGreaterThan(0);

    expect(DB::table('rebate_records')->where('status', 'in_bill')->count())->toBe(2);
    expect(DB::table('rebate_allocations')->where('settlement_bill_id', $playerBill->id)->count())
        ->toBeGreaterThan(0);
});
