import { test, expect } from '@playwright/test';
import {
    BASE_URL,
    USER,
    ADMIN,
    loginAs,
    ensureLiveRacingEnabled,
    createArena,
    createEventShowUrl,
    addRace,
    addHorses,
    offerSingleBetTypes,
    offerMultiBetTypeCombos,
    publishEvent,
    closeBetting,
    settleAndMarkRace,
} from '../helpers';

// A closed/settled race still appears in the betting wizard. A *settled* leg
// shows the finishing order + dividends in place of the picker; the "Place Bet"
// block is hidden while such a leg (or a multi-combo with any ran leg) is
// active; and the "betting is now closed" warning only shows while the *active*
// leg is a closed race with no result — it must not linger on a multi-combo's
// still-open legs, and must clear the instant you tab back to an open race
// (not after the 5s poll). See event.html.twig `updateClosedRaceState`.

test.describe('Live Racing wizard — closed/settled race behaviour', () => {
    test.setTimeout(180_000);

    test('settled leg shows result+dividends and hides Place Bet', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await ensureLiveRacingEnabled(page);

        const arena = await createArena(page, 'LRSettledLeg', { win: '10' });
        const { eventUrl, eventId } = await createEventShowUrl(page, arena);
        const r1 = await addRace(page, eventUrl, 1);
        const r2 = await addRace(page, eventUrl, 2);
        const h1 = await addHorses(page, r1.raceUrl, 4);
        await addHorses(page, r2.raceUrl, 4);
        await offerSingleBetTypes(page, eventUrl, [
            { key: 'win', raceId: r1.raceId },
            { key: 'win', raceId: r2.raceId },
        ]);
        await publishEvent(page, eventUrl);

        await closeBetting(page, r1.raceUrl);
        await saveFirstComboResult(page, r1.raceUrl, h1[0], '25.00');
        await settleAndMarkRace(page, r1.raceId);

        await loginAs(page, USER.mobile, USER.password);
        await page.goto(`${BASE_URL}/play/live-racing/${eventId}`);
        await page.click('[data-testid="tab-bet-key-win"]');
        const winPanel = page.locator('[data-testid="key-panel-win"]');
        const placeBet = page.locator('[data-testid="wizard-place-bet"]');
        const warning = page.locator('[data-testid="wizard-race-closed-warning"]');
        const activeLeg = winPanel.locator('.wizard-single-leg:not(.d-none)');

        // Defaults to the open race 2: picker + Place Bet, no warning.
        await expect(activeLeg.locator('.horse-row').first()).toBeVisible();
        await expect(placeBet).toBeVisible();
        await expect(warning).toBeHidden();

        // Tab to the settled race 1: result block, no picker, Place Bet hidden,
        // no warning (deliberately viewing a past result).
        await winPanel.locator(`[data-testid^="tab-race-${r1.raceId}-bet-"]`).click();
        await expect(winPanel.locator(`[data-testid="wizard-leg-finish-${r1.raceId}"]`)).toHaveText('1');
        await expect(winPanel.locator(`[data-testid="wizard-leg-dividends-${r1.raceId}"]`)).toContainText('₱25.00');
        await expect(activeLeg.locator('.horse-row')).toHaveCount(0);
        await expect(placeBet).toBeHidden();
        await expect(warning).toBeHidden();

        // Back to race 2: Place Bet returns, still no warning.
        await winPanel.locator(`[data-testid^="tab-race-${r2.raceId}-bet-"]`).click();
        await expect(placeBet).toBeVisible();
        await expect(warning).toBeHidden();
    });

    test('multi-race combo: warning follows the active leg, not "any leg ran"', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await ensureLiveRacingEnabled(page);

        const arena = await createArena(page, 'LRMultiLeg', { pick_4: '10' });
        const { eventUrl, eventId } = await createEventShowUrl(page, arena);
        const races = [];
        for (let n = 1; n <= 4; n++) {
            const r = await addRace(page, eventUrl, n);
            // 6 (not 4) horses so a race row's horse-count cell can't collide
            // with the race-number text addRace() filters on.
            await addHorses(page, r.raceUrl, 6);
            races.push(r);
        }
        await offerMultiBetTypeCombos(page, eventUrl, 'pick_4', [races.map(r => r.raceId)]);
        await publishEvent(page, eventUrl);

        // Race 1 (first Pick 4 leg): close + result + settle. Races 2-4 open.
        // Pick 4's dividend is only entered on its last leg, so race 1's result
        // needs just a finisher.
        await closeBetting(page, races[0].raceUrl);
        await saveFirstComboResult(page, races[0].raceUrl);
        await settleAndMarkRace(page, races[0].raceId);

        await loginAs(page, USER.mobile, USER.password);
        await page.goto(`${BASE_URL}/play/live-racing/${eventId}`);
        await page.click('[data-testid="tab-bet-key-pick_4"]');
        const panel = page.locator('[data-testid^="key-panel-pick_4"]');
        const placeBet = page.locator('[data-testid="wizard-place-bet"]');
        const warning = page.locator('[data-testid="wizard-race-closed-warning"]');

        // Defaults to race 2 (open): Place Bet hidden (race 1 already ran) but
        // NO warning — the active leg is open.
        await expect(placeBet).toBeHidden();
        await expect(warning).toBeHidden();

        // Tab to the settled race 1 leg: its result shows, still no warning.
        await panel.locator(`[data-testid^="tab-race-${races[0].raceId}-bet-"]`).click();
        await expect(panel.locator(`[data-testid="wizard-leg-result-${races[0].raceId}"]`)).toBeVisible();
        await expect(warning).toBeHidden();

        // Tab to still-open race 3: no warning (this was the bug — it used to
        // linger because "any leg ran").
        await panel.locator(`[data-testid^="tab-race-${races[2].raceId}-bet-"]`).click();
        await expect(warning).toBeHidden();
        await expect(placeBet).toBeHidden();

        // The whole combo is locked: key tab greyed, open legs' picks
        // disabled, closed-combo notice shown - but results stay viewable.
        await expect(page.locator('[data-testid="tab-bet-key-pick_4"]')).toHaveClass(/is-closed/);
        await expect(page.locator('[data-testid="wizard-combo-closed-notice"]')).toBeVisible();
        const race3Boxes = panel.locator(`[data-testid^="checkbox-leg-${races[2].raceId}-horse-"]`);
        expect(await race3Boxes.count()).toBeGreaterThan(0);
        for (const box of await race3Boxes.all()) {
            await expect(box).toBeDisabled();
        }
        await panel.locator(`[data-testid^="tab-race-${races[0].raceId}-bet-"]`).click();
        await expect(panel.locator(`[data-testid="wizard-leg-result-${races[0].raceId}"]`)).toBeVisible();
    });

    test('multi-combo key: a combo with a ran leg is locked, open combo is the default', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await ensureLiveRacingEnabled(page);

        const arena = await createArena(page, 'LRComboLock', { daily_double: '10' });
        const { eventUrl, eventId } = await createEventShowUrl(page, arena);
        const races = [];
        for (let n = 1; n <= 4; n++) {
            const r = await addRace(page, eventUrl, n);
            await addHorses(page, r.raceUrl, 6);
            races.push(r);
        }
        await offerMultiBetTypeCombos(page, eventUrl, 'daily_double', [
            [races[0].raceId, races[1].raceId],
            [races[2].raceId, races[3].raceId],
        ]);
        await publishEvent(page, eventUrl);

        // Race 1 (first leg of the R1-R2 combo): close + result + settle.
        await closeBetting(page, races[0].raceUrl);
        await saveFirstComboResult(page, races[0].raceUrl);
        await settleAndMarkRace(page, races[0].raceId);

        await loginAs(page, USER.mobile, USER.password);
        await page.goto(`${BASE_URL}/play/live-racing/${eventId}`);
        await page.click('[data-testid="tab-bet-key-daily_double"]');
        const keyPanel = page.locator('[data-testid="key-panel-daily_double"]');
        const notice = page.locator('[data-testid="wizard-combo-closed-notice"]');
        const closedCombo = keyPanel.locator('.wizard-combo-tab').filter({ hasText: `Race 1 - Race 2` });
        const openCombo = keyPanel.locator('.wizard-combo-tab').filter({ hasText: `Race 3 - Race 4` });

        // Key tab itself is not closed (one combo is still bettable).
        await expect(page.locator('[data-testid="tab-bet-key-daily_double"]')).not.toHaveClass(/is-closed/);

        // Defaults to the open R3-R4 combo: picks enabled, no notice.
        await expect(openCombo.locator('input')).toBeChecked();
        await expect(keyPanel.locator(`[data-testid^="checkbox-leg-${races[2].raceId}-horse-"]`).first()).toBeEnabled();
        await expect(notice).toBeHidden();

        // R1-R2 combo is marked closed but still clickable.
        await expect(closedCombo).toHaveClass(/is-closed/);
        await expect(closedCombo).toContainText('Closed');
        await closedCombo.click();
        await expect(notice).toBeVisible();
        await expect(page.locator('[data-testid="wizard-place-bet"]')).toBeHidden();
        const race2Boxes = keyPanel.locator(`[data-testid^="checkbox-leg-${races[1].raceId}-horse-"]`);
        for (const box of await race2Boxes.all()) {
            await expect(box).toBeDisabled();
        }

        // ...and race 1's result is still viewable from its race tab.
        await keyPanel.locator(`[data-testid^="tab-race-${races[0].raceId}-bet-"]`).click();
        await expect(keyPanel.locator(`[data-testid="wizard-leg-result-${races[0].raceId}"]`)).toBeVisible();
    });
});

// Saves a race result by filling the first winning-combination row of every
// bet-type block on the admin result form: `horseId` (or the first listed
// horse) in each slot, plus `dividend`. A leg race with no blocks of its own
// (e.g. a non-final multi-race leg) is saved as-is, which still records a result.
async function saveFirstComboResult(
    page: import('@playwright/test').Page,
    raceUrl: string,
    horseId?: string,
    dividend = '10.00',
): Promise<void> {
    await page.goto(`${BASE_URL}${raceUrl}`);
    const blocks = page.locator('[data-testid^="combo-bettype-"]');
    for (let b = 0; b < await blocks.count(); b++) {
        const row = blocks.nth(b).locator('[data-combo-row]').first();
        const selects = row.locator('select');
        for (let i = 0; i < await selects.count(); i++) {
            const sel = selects.nth(i);
            const wanted = horseId && await sel.locator(`option[value="${horseId}"]`).count() ? horseId : null;
            if (wanted) await sel.selectOption(wanted);
            else await sel.selectOption({ index: 1 });
        }
        await row.locator('input[type="number"]').fill(dividend);
    }
    page.once('dialog', d => d.accept());
    await page.click('[data-testid="btn-save-result"]');
    await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
}
