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

// Event lists are sorted by event date, not creation order, and this DB is shared
// (un-isolated) across spec files in the same test run, so the row we just created
// must be located by its unique date rather than by list position (.last()/.first()).
async function createEventRaceUrl(page: Page): Promise<string> {
    const dateStr = uniqueFutureDate();
    await page.goto(`${BASE_URL}/wfbo/events/new`);
    await page.selectOption('[data-testid="select-event-management"]', { index: 1 });
    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');
    await page.goto(`${BASE_URL}${eventHref}`);

    await page.click('[data-testid="btn-new-race"]');
    await page.fill('[data-testid="input-race-number"]', String(Date.now() % 1000));
    await page.click('[data-testid="btn-submit"]');

    const raceHref = await page.locator('[data-testid^="btn-view-race-"]').last().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 closeBetting(page: Page, raceUrl: string): Promise<void> {
    await page.goto(`${BASE_URL}${raceUrl}`);
    page.once('dialog', dialog => dialog.accept());
    await page.click('[data-testid="btn-close-betting"]');
    await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
}

test.describe('WFBO Event Race Results', () => {

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

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

        test('result section shows a hint while the race is open', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 1);
            await page.goto(`${BASE_URL}${raceUrl}`);

            await expect(page.getByText('Close betting to enter the result.')).toBeVisible();
            await expect(page.locator('[data-testid="result-form"]')).toHaveCount(0);
        });

        test('result-entry form appears once the race is closed', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 1);
            await addHorse(page, raceUrl, 2);
            await closeBetting(page, raceUrl);

            await expect(page.locator('[data-testid="result-form"]')).toBeVisible();
            await expect(page.locator('[data-testid="select-finisher-1"]')).toBeVisible();
            await expect(page.locator('[data-testid="select-finisher-2"]')).toBeVisible();
            await expect(page.locator('[data-testid="checkbox-dead-heat-1"]')).toBeVisible();
        });

        test('requires at least the winner to be selected', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 1);
            await closeBetting(page, raceUrl);

            page.once('dialog', dialog => dialog.accept());
            await page.click('[data-testid="btn-save-result"]');

            await expect(page.locator('[data-testid="flash-error"]').first()).toBeVisible();
            await expect(page.locator('[data-testid="flash-success"]')).toHaveCount(0);
        });

        test('rejects picking the same horse for two positions', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            const horse1 = await addHorse(page, raceUrl, 1);
            await addHorse(page, raceUrl, 2);
            await closeBetting(page, raceUrl);

            await page.selectOption('[data-testid="select-finisher-1"]', horse1);
            await page.selectOption('[data-testid="select-finisher-2"]', horse1);

            page.once('dialog', dialog => dialog.accept());
            await page.click('[data-testid="btn-save-result"]');

            await expect(page.locator('[data-testid="flash-error"]').first()).toBeVisible();
            await expect(page.locator('[data-testid="flash-success"]')).toHaveCount(0);
        });

        test('rejects a 3-way dead heat', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            const horse1 = await addHorse(page, raceUrl, 1);
            const horse2 = await addHorse(page, raceUrl, 2);
            const horse3 = await addHorse(page, raceUrl, 3);
            await closeBetting(page, raceUrl);

            await page.selectOption('[data-testid="select-finisher-1"]', horse1);
            await page.selectOption('[data-testid="select-finisher-2"]', horse2);
            await page.selectOption('[data-testid="select-finisher-3"]', horse3);
            await page.check('[data-testid="checkbox-dead-heat-1"]');
            await page.check('[data-testid="checkbox-dead-heat-2"]');

            page.once('dialog', dialog => dialog.accept());
            await page.click('[data-testid="btn-save-result"]');

            await expect(page.locator('[data-testid="flash-error"]').first()).toBeVisible();
            await expect(page.locator('[data-testid="flash-success"]')).toHaveCount(0);
        });

        test('can save a result with a dead heat, which settles the race and shows a read-only summary', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            const horse1 = await addHorse(page, raceUrl, 1);
            const horse2 = await addHorse(page, raceUrl, 2);
            const horse3 = await addHorse(page, raceUrl, 3);
            await closeBetting(page, raceUrl);

            await page.selectOption('[data-testid="select-finisher-1"]', horse1);
            await page.selectOption('[data-testid="select-finisher-2"]', horse2);
            await page.check('[data-testid="checkbox-dead-heat-1"]');
            await page.selectOption('[data-testid="select-finisher-3"]', horse3);

            page.once('dialog', dialog => dialog.accept());
            await page.click('[data-testid="btn-save-result"]');

            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
            await expect(page.locator('[data-testid="race-status"]')).toHaveText('Settled');
            await expect(page.locator('[data-testid="race-result-summary"]')).toBeVisible();
            await expect(page.locator('[data-testid="race-result-text"]')).toContainText('1. Horse #1 = Horse #2');
            await expect(page.locator('[data-testid="race-result-text"]')).toContainText('2. Horse #3');
            await expect(page.locator('[data-testid="result-form"]')).toHaveCount(0);
        });

        test('a settled race cannot be re-entered or re-scratched', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            const horse1 = await addHorse(page, raceUrl, 1);
            await closeBetting(page, raceUrl);

            await page.selectOption('[data-testid="select-finisher-1"]', horse1);
            page.once('dialog', dialog => dialog.accept());
            await page.click('[data-testid="btn-save-result"]');
            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();

            await page.goto(`${BASE_URL}${raceUrl}`);
            await expect(page.locator('[data-testid="result-form"]')).toHaveCount(0);
            await expect(page.locator('[data-testid="btn-save-scratches"]')).toHaveCount(0);
        });

        test('scratch-after-close with a substitute is bundled into the result save and persists', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            const horse1 = await addHorse(page, raceUrl, 1);
            const horse2 = await addHorse(page, raceUrl, 2);
            const horse3 = await addHorse(page, raceUrl, 3);
            await closeBetting(page, raceUrl);

            // Scratch horse 2 after close, with horse 3 as its substitute.
            await page.check(`[data-testid="checkbox-result-scratch-${horse2}"]`);
            await page.selectOption(`[data-testid="select-substitute-${horse2}"]`, horse3);

            // Finish order uses only the still-active horses (1 and 3).
            await page.selectOption('[data-testid="select-finisher-1"]', horse1);
            await page.selectOption('[data-testid="select-finisher-2"]', horse3);

            page.once('dialog', dialog => dialog.accept());
            await page.click('[data-testid="btn-save-result"]');

            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
            // The standalone Horses table is hidden once the race is closed
            // (scratching after close now happens exclusively through this
            // Result form's own "Scratch after close" section above) - the
            // settled read-only summary is the source of truth to check.
            await expect(page.locator('[data-testid="scratched-after-close-summary"]')).toContainText('substitute: Horse #3');
        });

        test('the Horses section is hidden once the race is closed', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 1);
            await expect(page.locator('[data-testid="horses-table"]')).toBeVisible();

            await closeBetting(page, raceUrl);
            await expect(page.locator('[data-testid="horses-table"]')).toHaveCount(0);
            await expect(page.locator('[data-testid="btn-save-scratches"]')).toHaveCount(0);
        });

    });

});
