import { test, expect, Page } from '@playwright/test';
import { BASE_URL, USER, AGENT, ADMIN, loginAs } from '../helpers';

test.describe('Video Karera Game', () => {

    test.beforeEach(async ({ page }) => {
        await loginAs(page, USER.mobile, USER.password);
    });

    test('game page loads at /play/video-karera', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        await expect(page.locator('#race-canvas-panel')).toBeVisible();
    });

    test('sticky wallet bar is visible on the game page', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        const bar = page.locator('[data-testid="wallet-bar"]');
        await expect(bar).toBeVisible();
        const text = await page.locator('[data-testid="wallet-bar"] #wallet-bar-amount').textContent();
        expect(text).toMatch(/₱/);
    });

    test('six horse selection buttons are present', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        for (let h = 1; h <= 6; h++) {
            await expect(page.locator(`[data-testid="horse-btn-${h}"]`)).toBeVisible();
        }
    });

    test('bet amount preset buttons are present', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        for (const amount of [1, 5, 10, 50, 100]) {
            await expect(page.locator(`[data-testid="bet-amount-btn-${amount}"]`)).toBeVisible();
        }
    });

    test('place bet button is disabled until two horses are selected', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        const btn = page.locator('[data-testid="btn-place-bet"]');
        await expect(btn).toBeVisible();
        await expect(btn).toBeDisabled();

        await page.click('[data-testid="horse-btn-1"]');
        await expect(btn).toBeDisabled();

        await page.click('[data-testid="horse-btn-3"]');
        await expect(btn).toBeEnabled();
    });

    test('dividend table renders 15 horse-pair cells', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        const cells = page.locator('.dividend-cell[data-pair]');
        await expect(cells).toHaveCount(15);
    });

    test('clicking a dividend cell selects that pair and enables bet button', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        await page.locator('.dividend-cell[data-pair="1-2"]').click();
        await expect(page.locator('[data-testid="btn-place-bet"]')).toBeEnabled();
    });

    test('race state API returns JSON with a state field', async ({ page }) => {
        await loginAs(page, USER.mobile, USER.password);
        const response = await page.request.get(`${BASE_URL}/play/video-karera/state`, {
            headers: { 'X-Requested-With': 'XMLHttpRequest' },
        });
        expect(response.ok()).toBeTruthy();
        const body = await response.json();
        expect(['betting_open', 'betting_closed', 'finished', 'no_race']).toContain(body.state);
    });

    test('race history page loads at /play/video-karera/history', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera/history`);
        await expect(page.locator('[data-testid="race-history-title"]')).toBeVisible();
    });

    test('race history page shows table or empty state', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera/history`);
        const table = page.locator('[data-testid="race-history-table"]');
        const empty = page.locator('[data-testid="race-history-empty"]');
        const hasTable = await table.count() > 0;
        const hasEmpty = await empty.count() > 0;
        expect(hasTable || hasEmpty).toBeTruthy();
    });

    test('race history back link returns to game', async ({ page }) => {
        await page.goto(`${BASE_URL}/play/video-karera/history`);
        await page.click('[data-testid="race-history-back-link"]');
        await expect(page).toHaveURL(`${BASE_URL}/play/video-karera`);
    });

    test('unauthenticated access redirects to /login', async ({ page }) => {
        await page.context().clearCookies();
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        expect(page.url()).toContain('/login');
    });

});

async function topUpWalletForUser(page: Page, targetMobile: string, amount: number): Promise<void> {
    await loginAs(page, ADMIN.mobile, ADMIN.password);
    await page.goto(`${BASE_URL}/wfbo/users?search=${encodeURIComponent(targetMobile)}`);
    const userRow = page.locator('[data-testid^="user-row-"]').filter({ hasText: targetMobile });
    const rowId = (await userRow.first().getAttribute('data-testid'))?.replace('user-row-', '');
    await page.goto(`${BASE_URL}/wfbo/users/${rowId}/transactions`);
    await page.fill('[data-testid="adj-amount"]', String(amount));
    await page.fill('[data-testid="adj-reason"]', 'Bet acceptance test setup');
    await page.click('[data-testid="adj-submit"]');
    await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
}

async function getRaceState(page: Page): Promise<string> {
    const resp = await page.request.get(`${BASE_URL}/play/video-karera/state`, {
        headers: { 'X-Requested-With': 'XMLHttpRequest' },
    });
    return (await resp.json()).state;
}

test.describe('Video Karera — Bet Placement & Wallet Deduction', () => {

    test.beforeAll(async ({ browser }) => {
        const page = await browser.newPage();
        await topUpWalletForUser(page, USER.mobile, 200);
        await page.close();
    });

    test.beforeEach(async ({ page }) => {
        await loginAs(page, USER.mobile, USER.password);
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
    });

    test('wallet balance decreases by bet amount when a bet is placed', async ({ page }) => {
        const state = await getRaceState(page);
        test.skip(state !== 'betting_open', 'Race is not in betting_open state');

        const balanceBefore = parseFloat(
            (await page.locator('[data-testid="wallet-balance"]').textContent() ?? '')
                .replace(/[^\d.]/g, ''),
        );

        await page.locator('.dividend-cell[data-pair="1-2"]').click();
        await page.locator('[data-testid="bet-amount-btn-10"]').click();
        await page.locator('[data-testid="btn-place-bet"]').click();

        await page.waitForLoadState('networkidle');

        try {
            await page.waitForFunction(
                (before: number) => {
                    const el = document.querySelector('[data-testid="wallet-balance"]');
                    const val = parseFloat((el?.textContent ?? '').replace(/[^\d.]/g, ''));
                    return val < before;
                },
                balanceBefore,
                { timeout: 10000 },
            );
        } catch {
            const betRejected = await page.locator('[data-testid="bet-error"]').isVisible();
            test.skip(betRejected, 'Bet rejected — race closed between state check and bet click');
            return;
        }

        const balanceAfter = parseFloat(
            (await page.locator('[data-testid="wallet-balance"]').textContent() ?? '')
                .replace(/[^\d.]/g, ''),
        );
        expect(balanceAfter).toBeCloseTo(balanceBefore - 10, 1);
    });

    test('bet exceeding wallet balance shows insufficient funds error', async ({ page }) => {
        const state = await getRaceState(page);
        test.skip(state !== 'betting_open', 'Race is not in betting_open state');

        await page.locator('.dividend-cell[data-pair="1-2"]').click();
        await page.evaluate(() => {
            (document.getElementById('bet-amount') as HTMLInputElement).value = '999999';
        });
        await page.locator('[data-testid="btn-place-bet"]').click();

        await expect(page.locator('[data-testid="bet-error"]')).toBeVisible({ timeout: 5000 });
    });

    test('placed bet appears in the bets history tab', async ({ page }) => {
        const state = await getRaceState(page);
        test.skip(state !== 'betting_open', 'Race is not in betting_open state');

        await page.locator('.dividend-cell[data-pair="2-3"]').click();
        await page.locator('[data-testid="bet-amount-btn-5"]').click();
        await page.locator('[data-testid="btn-place-bet"]').click();

        // Wait for the bet-error to stay hidden (success path)
        await page.waitForFunction(
            () => {
                const errEl = document.getElementById('bet-error');
                return !errEl || errEl.style.display === 'none' || errEl.textContent === '';
            },
            null,
            { timeout: 5000 },
        );

        await page.goto(`${BASE_URL}/transactions`);
        await page.click('[data-testid="tab-bets"]');
        await expect(page.locator('[data-testid="bets-table"]')).toBeVisible();
        await expect(page.locator('[data-testid="bets-table"] tbody tr').first()).toBeVisible();
    });

});

test.describe('Video Karera — Revenue Cap (30% rule)', () => {

    test.beforeEach(async ({ page }) => {
        await loginAs(page, USER.mobile, USER.password);
    });

    test('finished race state response includes valid winningPair and positive dividend', async ({ page }) => {
        const resp = await page.request.get(`${BASE_URL}/play/video-karera/state`, {
            headers: { 'X-Requested-With': 'XMLHttpRequest' },
        });
        expect(resp.ok()).toBeTruthy();
        const body = await resp.json();

        test.skip(body.state !== 'finished', `Race is not finished (state: ${body.state})`);

        expect(Array.isArray(body.winningPair)).toBeTruthy();
        expect(body.winningPair).toHaveLength(2);

        const [lo, hi] = body.winningPair as [number, number];
        expect(lo).toBeGreaterThanOrEqual(1);
        expect(hi).toBeLessThanOrEqual(6);
        expect(lo).toBeLessThan(hi);

        expect(typeof body.dividend).toBe('string');
        expect(parseFloat(body.dividend)).toBeGreaterThanOrEqual(0);
        expect(isNaN(parseFloat(body.dividend))).toBe(false);
    });

    test('non-finished race state response has null winningPair and no dividend', async ({ page }) => {
        const resp = await page.request.get(`${BASE_URL}/play/video-karera/state`, {
            headers: { 'X-Requested-With': 'XMLHttpRequest' },
        });
        const body = await resp.json();

        test.skip(body.state === 'finished' || body.state === 'no_race', `Race is ${body.state}`);

        expect(body.winningPair).toBeNull();
        expect(body.result).toBeNull();
        expect(body.dividend).toBeUndefined();
    });

    test('finished race result array contains all 6 horses exactly once', async ({ page }) => {
        const resp = await page.request.get(`${BASE_URL}/play/video-karera/state`, {
            headers: { 'X-Requested-With': 'XMLHttpRequest' },
        });
        const body = await resp.json();

        test.skip(body.state !== 'finished', `Race is not finished (state: ${body.state})`);

        expect(Array.isArray(body.result)).toBeTruthy();
        expect(body.result).toHaveLength(6);

        const sorted = [...body.result].sort((a: number, b: number) => a - b);
        expect(sorted).toEqual([1, 2, 3, 4, 5, 6]);

        // Effective winner must be at positions 0-1
        const [pos0, pos1] = body.result as [number, number];
        const [lo, hi]     = body.winningPair as [number, number];
        expect(Math.min(pos0, pos1)).toBe(lo);
        expect(Math.max(pos0, pos1)).toBe(hi);
    });

    test('bet on effective winning pair is settled as won with correct payout', async ({ page }) => {
        // This test requires a race to be in finished state AND the user must have an existing
        // won bet from a previous race in their transaction history.
        await page.goto(`${BASE_URL}/transactions`);
        await page.click('[data-testid="tab-bets"]');

        const betsTable = page.locator('[data-testid="bets-table"]');
        const hasTable  = await betsTable.count() > 0;

        test.skip(!hasTable, 'No bet history available to verify payout');

        // Find any row with a "won" status to verify payout is present
        const wonRow = betsTable.locator('tbody tr').filter({ hasText: 'won' }).first();
        const hasWon = await wonRow.count() > 0;

        test.skip(!hasWon, 'No won bets in history yet');

        // Payout cell must show a numeric amount (not empty or zero)
        const payoutCell = wonRow.locator('[data-testid="bet-payout"]');
        await expect(payoutCell).toBeVisible();
        const payoutText = await payoutCell.textContent() ?? '';
        const payoutNum  = parseFloat(payoutText.replace(/[^\d.]/g, ''));
        expect(payoutNum).toBeGreaterThan(0);
    });

});

test.describe('Video Karera — Commission referral registration', () => {

    test('new user can register with AGENT referral code and access game', async ({ page }) => {
        // Step 1: Get the actual referral code from the AGENT's dashboard (do not hardcode)
        await loginAs(page, AGENT.mobile, AGENT.password);
        await page.goto(`${BASE_URL}/agent/dashboard`);
        const codeInput = page.locator('[data-testid="referral-code-display"]');
        await expect(codeInput).toBeVisible();
        const agentReferralCode = await codeInput.inputValue();
        expect(agentReferralCode).toMatch(/^[A-F0-9]{8}$/);

        // Step 2: Register a new user using the actual code
        const ts       = Date.now();
        const mobile   = `+639${ts.toString().slice(-9)}`;
        const password = 'TestPass1!';

        await page.context().clearCookies();
        await page.goto(`${BASE_URL}/register`);
        await page.fill('[data-testid="input-first-name"]', 'Referred');
        await page.fill('[data-testid="input-last-name"]',  'Player');
        await page.fill('[data-testid="input-mobile-number"]', mobile);
        await page.fill('[data-testid="input-password"]',   password);
        await page.fill('[data-testid="input-password-confirm"]', password);
        await page.fill('[data-testid="input-referral-code"]', agentReferralCode);
        await page.click('[data-testid="btn-register"]');
        await page.waitForURL(`${BASE_URL}/login`);

        // Step 3: Clear AGENT's session cookies so we can log in as the new user
        await page.context().clearCookies();
        await loginAs(page, mobile, password);

        // Step 4: Verify the referred user can access the game page
        await page.goto(`${BASE_URL}/play/video-karera`, { waitUntil: 'domcontentloaded' });
        await expect(page.locator('[data-testid="wallet-balance"]')).toBeVisible();

        // Step 5: Verify agent's transaction list is accessible
        await loginAs(page, AGENT.mobile, AGENT.password);
        await page.goto(`${BASE_URL}/agent/transactions`);
        await expect(page.locator('[data-testid="agent-tx-table"]')).toBeVisible();
    });

});
