import { test, expect, type Page } from '@playwright/test';
import {
    BASE_URL,
    ADMIN,
    AGENT,
    AUDITOR,
    loginAs,
    registerAndLogin,
    registerUserWithReferralCode,
    adjustWalletAsAuditor,
} from '../helpers';

// Mini Games write their bets and wins to the player's wallet ledger
// (/transactions): one "Bet" row per placement and a "Win" row when it pays,
// so the Balance column always adds up. Pachinko exercises it here - the
// outcome is random, so the expectations are derived from the bet response.

async function ensurePachinkoEnabled(page: Page): Promise<void> {
    await loginAs(page, ADMIN.mobile, ADMIN.password);
    await page.goto(`${BASE_URL}/wfbo/pachinko/settings`, { waitUntil: 'domcontentloaded' });
    const toggle = page.locator('[data-testid="toggle-pk-enabled"]');
    if (!(await toggle.isChecked())) {
        await toggle.check();
        await page.click('[data-testid="btn-save-pk-settings"]');
        await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
    }
}

/** Sets the shared Mini Games agent commission rate (%) on WFBO ▸ Settings. */
async function setMiniGamesCommissionRate(page: Page, rate: string): Promise<void> {
    await loginAs(page, ADMIN.mobile, ADMIN.password);
    await page.goto(`${BASE_URL}/wfbo/settings`, { waitUntil: 'domcontentloaded' });
    await page.fill('[data-testid="input-agent-commission-rate"]', rate);
    await page.click('[data-testid="btn-save-settings"]');
    await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
}

/** Drops one ball through Pachinko's bet endpoint as the logged-in player; returns the payout. */
async function dropPachinkoBall(page: Page, amount: string): Promise<number> {
    // The CSRF token and bet URL are inlined in the game page's script -
    // read them from the served HTML rather than racing the page's JS.
    const html   = await (await page.request.get(`${BASE_URL}/play/pachinko`)).text();
    const token  = html.match(/const CSRF_TOKEN='([^']+)'/)?.[1];
    const betUrl = html.match(/const BET_URL='([^']+)'/)?.[1];
    expect(token, 'pachinko page exposes its CSRF token').toBeTruthy();
    expect(betUrl, 'pachinko page exposes its bet URL').toBeTruthy();
    const res = await page.request.post(`${BASE_URL}${betUrl}`, { form: { _token: token!, amount } });
    expect(res.ok(), await res.text()).toBeTruthy();

    return parseFloat((await res.json()).payout);
}

function peso(amount: number): string {
    return `₱${amount.toFixed(2)}`;
}

test.describe('Mini Games — bets and wins in the wallet ledger', () => {
    test.setTimeout(120_000);

    test('a Pachinko drop writes a Bet row, and a Win row when it pays', async ({ page }) => {
        await ensurePachinkoEnabled(page);
        const player = await registerAndLogin(page);
        await loginAs(page, AUDITOR.mobile, AUDITOR.password);
        await adjustWalletAsAuditor(page, player.mobile, '100', 'Mini games ledger e2e');

        // Drop one ₱10 ball through the game's own bet endpoint.
        await loginAs(page, player.mobile, player.password);
        const payout = await dropPachinkoBall(page, '10');

        await page.goto(`${BASE_URL}/transactions`);
        const rows = page.locator('[data-testid^="transaction-row-"]');

        const betRow = rows.filter({ hasText: 'Pachinko bet' });
        await expect(betRow).toHaveCount(1);
        await expect(betRow).toContainText('Bet');
        await expect(betRow).toContainText('-₱10.00');
        await expect(betRow).toContainText(peso(90));

        const winRow = rows.filter({ hasText: 'Pachinko win' });
        if (payout > 0) {
            await expect(winRow).toHaveCount(1);
            await expect(winRow).toContainText(`+${peso(payout)}`);
            await expect(winRow).toContainText(peso(90 + payout));
        } else {
            await expect(winRow).toHaveCount(0);
        }
    });

    test('the referring agent gets a Commission row for a referred player\'s bet', async ({ page }) => {
        await ensurePachinkoEnabled(page);
        await setMiniGamesCommissionRate(page, '10');

        // AGENT is the fixture master agent with referral code ABCDEF01.
        const player = await registerUserWithReferralCode(page, 'ABCDEF01');
        await adjustWalletAsAuditor(page, player.mobile, '100', 'Mini games commission e2e');

        await loginAs(page, player.mobile, player.password);
        await dropPachinkoBall(page, '10');

        // 10% of the ₱10 stake -> ₱1.00 to the master agent.
        await loginAs(page, AGENT.mobile, AGENT.password);
        await page.goto(`${BASE_URL}/transactions`);
        const commissionRows = page.locator('[data-testid^="transaction-row-"]', { hasText: 'Commission — Pachinko bet by Referred Player' });
        await expect(commissionRows.first()).toBeVisible();
        await expect(commissionRows.first()).toContainText('Commission');
        await expect(commissionRows.first()).toContainText('+₱1.00');
    });
});
