import { promises as fs } from 'fs';
import { test, expect, Page } from '@playwright/test';
import {
    BASE_URL,
    ADMIN,
    AUDITOR,
    loginAs,
    registerAndLogin,
    ensureLiveRacingEnabled,
    createArena,
    createEventShowUrl,
    addRace,
    addHorses,
    offerSingleBetTypes,
    publishEvent,
    placeWizardBet,
    closeBetting,
    saveResult,
    settleAndMarkRace,
    adjustWalletAsAuditor,
} from '../helpers';

// WFBO event page ▸ "Win Rates" tab: per race × bet type, tickets-won %
// (won / settled tickets) and payout % (payout / stake), settled bets only.

async function dividendRowId(page: Page, label: RegExp): Promise<string> {
    const blocks = page.locator('[data-testid^="combo-bettype-"]');
    for (let i = 0; i < (await blocks.count()); i++) {
        const text = (await blocks.nth(i).locator('label.fw-semibold').first().textContent())
            ?.replace(/\s+/g, ' ').replace(/\s*\([\d-]+…\)\s*$/u, '').trim() ?? '';
        if (label.test(text)) {
            return (await blocks.nth(i).getAttribute('data-testid'))?.replace('combo-bettype-', '') ?? '';
        }
    }
    throw new Error(`no combination block for ${label}`);
}

test.describe('WFBO event — Win Rates tab', () => {
    test.setTimeout(240_000);

    test('shows win % and payout % per race and bet type after settlement', async ({ page }) => {
        // Two funded players.
        const players = [await registerAndLogin(page), await registerAndLogin(page)];
        await loginAs(page, AUDITOR.mobile, AUDITOR.password);
        for (const p of players) {
            await adjustWalletAsAuditor(page, p.mobile, '100', 'Win rates e2e');
        }

        // Event: race 1 offers Win + Forecast, race 2 offers Win only.
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await ensureLiveRacingEnabled(page);
        const arena = await createArena(page, 'WinRates', { win: '10', forecast: '10' });
        const { eventUrl, eventId } = await createEventShowUrl(page, arena);
        const race1 = await addRace(page, eventUrl, 1);
        const race2 = await addRace(page, eventUrl, 2);
        const horses = await addHorses(page, race1.raceUrl, 4);
        await addHorses(page, race2.raceUrl, 4);
        await offerSingleBetTypes(page, eventUrl, [
            { key: 'win', raceId: race1.raceId },
            { key: 'win', raceId: race2.raceId },
            { key: 'forecast', raceId: race1.raceId },
        ]);
        await publishEvent(page, eventUrl);

        // Before any settlement: offered cells say so, nothing is counted.
        await page.goto(`${BASE_URL}${eventUrl}?tab=win-rates`);
        await expect(page.locator('[data-testid="tab-win-rates"]')).toHaveClass(/is-active/);
        await expect(page.locator(`[data-testid="wr-${race1.raceId}-win"]`)).toContainText('No settled bets');

        // Player A backs horse 1, player B horse 2 - both Win on race 1.
        for (const [i, p] of players.entries()) {
            await loginAs(page, p.mobile, p.password);
            await placeWizardBet(page, {
                eventId, raceId: race1.raceId, cardLabel: 'Win',
                positions: { 1: [horses[i]] }, amount: '10',
            });
        }

        // Horse 1 wins race 1; settle.
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await closeBetting(page, race1.raceUrl);
        await page.goto(`${BASE_URL}${race1.raceUrl}`);
        // Every bet type offered on the race needs its winning combination.
        const winId      = await dividendRowId(page, /^Win$/);
        const forecastId = await dividendRowId(page, /^Forecast$/);
        await saveResult(page, race1.raceUrl, {
            combinations: {
                [winId]:      [{ horseIds: [horses[0]], dividend: '30.00' }],
                [forecastId]: [{ horseIds: [horses[0], horses[1]], dividend: '50.00' }],
            },
        });
        await settleAndMarkRace(page, race1.raceId);

        await page.goto(`${BASE_URL}${eventUrl}?tab=win-rates`);
        const table = page.locator('[data-testid="win-rates-table"]');
        await expect(table).toBeVisible();
        await expect(page.locator('[data-testid="wr-col-win"]')).toHaveText('Win');
        await expect(page.locator('[data-testid="wr-col-forecast"]')).toHaveText('Forecast');

        const r1Win = page.locator(`[data-testid="wr-${race1.raceId}-win"]`);
        await expect(r1Win.locator('[data-role="win-rate"]')).toHaveText('50.0%');
        await expect(r1Win.locator('[data-role="won-settled"]')).toHaveText('1/2 won');
        // Headline is payout %: 2 × ₱10 staked, the winner paid ₱30 → 150.0%.
        // Over 100% = the house lost → red (under 100% would be green).
        await expect(r1Win.locator('[data-role="payout-rate"]')).toHaveText('150.0%');
        await expect(r1Win.locator('.wr-rate')).toHaveClass(/wr-cold/);
        await expect(r1Win.locator('.wr-rate')).toHaveAttribute('title', /House lost/);

        // Offered but no settled bets / not offered at all.
        await expect(page.locator(`[data-testid="wr-${race1.raceId}-forecast"]`)).toContainText('No settled bets');
        await expect(page.locator(`[data-testid="wr-${race2.raceId}-forecast"]`)).toHaveText('—');
        await expect(page.locator(`[data-testid="wr-${race2.raceId}-win"]`)).toContainText('No settled bets');

        // Totals.
        await expect(page.locator('[data-testid="wr-total-win"] [data-role="won-settled"]')).toHaveText('1/2 won');
        await expect(page.locator('[data-testid="wr-total-all"] [data-role="win-rate"]')).toHaveText('50.0%');
        await expect(page.locator('[data-testid="wr-total-all"] [data-role="payout-rate"]')).toHaveText('150.0%');
        await expect(page.locator(`[data-testid="wr-${race1.raceId}-all"] [data-role="won-settled"]`)).toHaveText('1/2 won');

        // Export PDF (A4 landscape) downloads the same matrix.
        const [download] = await Promise.all([
            page.waitForEvent('download'),
            page.click('[data-testid="btn-export-win-rates-pdf"]'),
        ]);
        expect(download.suggestedFilename()).toMatch(/^win-rates-.+-\d{8}\.pdf$/);
        const pdf = await fs.readFile((await download.path()) as string);
        expect(pdf.subarray(0, 5).toString()).toBe('%PDF-');
        expect(pdf.toString('latin1')).toMatch(/\/MediaBox \[0\.0+ 0\.0+ 841\.89\d* 595\.2\d*\]/);
    });
});
