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

// Setup helpers mirror tests/acceptance_test/front/live_racing.spec.ts.

async function createArena(page: Page, betTypeKey: string, amount: string): Promise<string> {
    const name = `Bets Arena ${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
    const fieldTestId = 'input-' + betTypeKey.replace(/_/g, '-') + '-amount';

    await page.goto(`${BASE_URL}/wfbo/managements/new`);
    await page.fill('[data-testid="input-name"]', name);
    await page.fill(`[data-testid="${fieldTestId}"]`, amount);
    await page.click('[data-testid="btn-submit"]');
    await expect(page).toHaveURL(`${BASE_URL}/wfbo/managements`);

    return name;
}

async function createEventShowUrl(page: Page, arenaName: string): Promise<string> {
    const dateStr = uniqueFutureDate();
    await page.goto(`${BASE_URL}/wfbo/events/new`);
    await page.selectOption('[data-testid="select-event-management"]', { label: arenaName });
    await page.fill('[data-testid="input-event-date"]', dateStr);
    await page.click('[data-testid="btn-submit"]');
    await expect(page).toHaveURL(`${BASE_URL}/wfbo/events`);

    const row = page.locator('[data-testid^="event-row-"]').filter({ hasText: dateStr });
    const eventHref = await row.locator('[data-testid^="btn-view-"]').getAttribute('href');
    return eventHref ?? '';
}

async function addRace(page: Page, eventUrl: string, raceNumber: number): Promise<string> {
    await page.goto(`${BASE_URL}${eventUrl}`);
    await page.click('[data-testid="btn-new-race"]');
    await page.fill('[data-testid="input-race-number"]', String(raceNumber));
    await page.click('[data-testid="btn-submit"]');

    const row = page.locator('[data-testid^="race-row-"]').filter({ hasText: String(raceNumber) });
    const raceHref = await row.locator('[data-testid^="btn-view-race-"]').getAttribute('href');
    return raceHref ?? '';
}

async function addHorse(page: Page, raceUrl: string, horseNumber: number): Promise<string> {
    await page.goto(`${BASE_URL}${raceUrl}`);
    await page.click('[data-testid="btn-new-horse"]');
    await page.fill('[data-testid="input-horse-number"]', String(horseNumber));
    await page.fill('[data-testid="input-horse-name"]', `Horse ${horseNumber}`);
    await page.fill('[data-testid="input-horse-jockey"]', `Jockey ${horseNumber}`);
    await page.click('[data-testid="btn-submit"]');

    const row = page.locator('[data-testid^="horse-row-"]').last();
    const horseId = (await row.getAttribute('data-testid'))?.replace('horse-row-', '');
    return horseId ?? '';
}

async function offerSingleBetType(page: Page, eventUrl: string, key: string, raceId: string): Promise<void> {
    await page.goto(`${BASE_URL}${eventUrl}?tab=bet-types`);
    await page.check(`[data-testid="checkbox-leg-${key}-${raceId}"]`);
    await page.click('[data-testid="btn-save-bet-types"]');
    await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
}

async function publishEvent(page: Page, eventUrl: string): Promise<void> {
    await page.goto(`${BASE_URL}${eventUrl}`);
    page.once('dialog', dialog => dialog.accept());
    await page.click('[data-testid="btn-publish-event"]');
}

/**
 * Full setup: arena + published event with one open race and 2 horses, Win
 * offered, Live Racing enabled, and one straight Win bet placed as USER.
 * Leaves the browser logged in as ADMIN. Returns the placed bet's reference
 * number, found via the player's own history page (its testid embeds no
 * reference, so this reads the visible text directly).
 */
async function placeAWinBet(page: Page, arenaAmount = '10.00', raceNumber = Date.now() % 1000): Promise<{ arenaName: string; eventUrl: string; eventId: string; raceId: string; raceNumber: number; reference: string }> {
    await loginAs(page, ADMIN.mobile, ADMIN.password);

    const arenaName = await createArena(page, 'win', arenaAmount);
    const eventUrl  = await createEventShowUrl(page, arenaName);
    const eventId   = eventUrl.split('/').pop() ?? '';
    const raceUrl   = await addRace(page, eventUrl, raceNumber);
    const raceId    = raceUrl.split('/').pop() ?? '';
    const horse1    = await addHorse(page, raceUrl, 1);
    await addHorse(page, raceUrl, 2);

    await offerSingleBetType(page, eventUrl, 'win', raceId);
    await publishEvent(page, eventUrl);
    await ensureLiveRacingEnabled(page);

    await loginAs(page, USER.mobile, USER.password);
    await placeWizardBet(page, { eventId, raceId, cardLabel: /^Win$/, positions: { 1: [horse1] } });

    await page.goto(`${BASE_URL}/play/live-racing/history`);
    const row = page.locator(`[data-testid^="live-racing-history-row-"][data-arena="${arenaName}"]`);
    await expect(row).toBeVisible();
    const reference = ((await row.textContent()) ?? '').match(/Ref:\s*(\S+)/)?.[1] ?? '';

    await loginAs(page, ADMIN.mobile, ADMIN.password);

    return { arenaName, eventUrl, eventId, raceId, raceNumber, reference };
}

test.describe('WFBO Live Racing Bets', () => {

    test.describe('access control', () => {

        test('admin can view the live racing bets page', async ({ page }) => {
            await loginAs(page, ADMIN.mobile, ADMIN.password);
            await page.goto(`${BASE_URL}/wfbo/live-racing/bets`);

            await expect(page.locator('[data-testid="wfbo-sidebar"]')).toBeVisible();
            await expect(page.locator('[data-testid="live-racing-bets-table"], [data-testid="empty-state"]')).toBeVisible();
        });

        test('regular user cannot access the live racing bets page', async ({ page }) => {
            await loginAs(page, USER.mobile, USER.password);
            await page.goto(`${BASE_URL}/wfbo/live-racing/bets`);

            await expect(page.locator('[data-testid="wfbo-sidebar"]')).not.toBeVisible();
        });

        test('agent cannot access the live racing bets page', async ({ page }) => {
            await loginAs(page, AGENT.mobile, AGENT.password);
            await page.goto(`${BASE_URL}/wfbo/live-racing/bets`);

            await expect(page.locator('[data-testid="wfbo-sidebar"]')).not.toBeVisible();
        });

    });

    test.describe('browsing as admin', () => {

        test('a placed bet appears in the list with the correct columns', async ({ page }) => {
            const { reference } = await placeAWinBet(page);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month`);
            const row = page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference });

            await expect(row).toContainText('Win');
            await expect(row).toContainText('₱10.00');
            await expect(row).toContainText('Pending');
        });

        test('filtering by status narrows the list to matching bets only', async ({ page }) => {
            const { reference } = await placeAWinBet(page);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&status=pending`);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference })).toHaveCount(1);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&status=won`);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference })).toHaveCount(0);
        });

        test('filtering by reference number finds the exact bet', async ({ page }) => {
            const { reference } = await placeAWinBet(page);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&reference=${encodeURIComponent(reference)}`);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]')).toHaveCount(1);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').first()).toContainText(reference);
        });

        test('filtering by event narrows the list to that event only', async ({ page }) => {
            const first  = await placeAWinBet(page);
            const second = await placeAWinBet(page);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&event_id=${first.eventId}`);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: first.reference })).toHaveCount(1);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: second.reference })).toHaveCount(0);
        });

        test('filtering by bet type narrows the list to matching bets only', async ({ page }) => {
            const { reference, eventId } = await placeAWinBet(page);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&event_id=${eventId}&bet_type=win`);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference })).toHaveCount(1);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&event_id=${eventId}&bet_type=trifecta`);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference })).toHaveCount(0);
        });

        test('filtering by race number narrows the list to matching bets only', async ({ page }) => {
            const { reference, eventId, raceNumber } = await placeAWinBet(page, '10.00', 13);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&event_id=${eventId}&race_number=${raceNumber}`);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference })).toHaveCount(1);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&event_id=${eventId}&race_number=${raceNumber + 1}`);
            await expect(page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference })).toHaveCount(0);
        });

        test('the stats row reflects the filtered bets', async ({ page }) => {
            const { eventId } = await placeAWinBet(page);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&event_id=${eventId}`);
            await expect(page.locator('[data-testid="stat-total"]')).toHaveText('1');
            await expect(page.locator('[data-testid="stat-pending"]')).toHaveText('1');
        });

    });

    test.describe('cancel + refund (SUPER_ADMIN discretionary override)', () => {

        test('a plain ADMIN does not see a Cancel action', async ({ page }) => {
            const { reference } = await placeAWinBet(page);

            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month`);
            const row = page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference });
            await expect(row.locator('[data-testid^="btn-cancel-bet-"]')).toHaveCount(0);
        });

        test('SUPER_ADMIN can cancel a pending ticket, refunding the stake and recording an optional note', async ({ page }) => {
            const arenaAmount = '10.00';
            const { reference } = await placeAWinBet(page, arenaAmount);
            const balanceBefore = await readUserWalletAsAdmin(page, USER.mobile);

            await loginAs(page, SUPER_ADMIN.mobile, SUPER_ADMIN.password);
            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&reference=${encodeURIComponent(reference)}`);

            const row = page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference });
            await row.locator('[data-testid^="btn-cancel-bet-"]').click();

            const modal = page.locator('#cancelBetModal');
            await expect(modal).toBeVisible();
            await expect(modal.locator('#cancelBetMessage')).toContainText(`₱${arenaAmount}`);
            await modal.locator('[data-testid="input-cancel-note"]').fill('Cancelled for acceptance test verification.');
            await modal.locator('[data-testid="btn-confirm-cancel-bet"]').click();

            await expect(row.locator('[data-testid^="cancel-bet-result-"]')).toContainText('cancelled');
            await expect(row.locator('[data-testid^="badge-status-"]')).toHaveText('Void');
            await expect(row.locator('[data-testid^="btn-cancel-bet-"]')).not.toBeVisible();

            const balanceAfter = await readUserWalletAsAdmin(page, USER.mobile);
            expect(balanceAfter).toBeCloseTo(balanceBefore + parseFloat(arenaAmount), 2);
        });

        test('closing the confirmation modal without confirming leaves the bet untouched', async ({ page }) => {
            const { reference } = await placeAWinBet(page);

            await loginAs(page, SUPER_ADMIN.mobile, SUPER_ADMIN.password);
            await page.goto(`${BASE_URL}/wfbo/live-racing/bets?period=this_month&reference=${encodeURIComponent(reference)}`);

            const row = page.locator('[data-testid^="live-racing-bet-row-"]').filter({ hasText: reference });
            await row.locator('[data-testid^="btn-cancel-bet-"]').click();

            const modal = page.locator('#cancelBetModal');
            await expect(modal).toBeVisible();
            await modal.locator('.modal-footer .btn-secondary').click();
            await expect(modal).not.toBeVisible();

            await expect(row.locator('[data-testid^="badge-status-"]')).toHaveText('Pending');
            await expect(row.locator('[data-testid^="btn-cancel-bet-"]')).toBeVisible();
        });

    });

});
