import { test, expect, Page } from '@playwright/test';
import { BASE_URL, ADMIN, AGENT, USER, 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<void> {
    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"]');
}

async function publishEventFromRacePage(page: Page): Promise<void> {
    const eventUrl = await page.locator('a.back-link').getAttribute('href');
    await page.goto(`${BASE_URL}${eventUrl}`);
    page.once('dialog', dialog => dialog.accept());
    await page.click('[data-testid="btn-publish-event"]');
    await expect(page.locator('[data-testid="event-status"]')).toHaveText('Published');
}

test.describe('WFBO Horses', () => {

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

        test('regular user cannot access a race detail page', async ({ page }) => {
            await loginAs(page, USER.mobile, USER.password);
            await page.goto(`${BASE_URL}/wfbo/event-races/1`);

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

        test('agent cannot access a race detail page', async ({ page }) => {
            await loginAs(page, AGENT.mobile, AGENT.password);
            await page.goto(`${BASE_URL}/wfbo/event-races/1`);

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

    });

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

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

        test('new horse form has number/name/jockey fields but no status field', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await page.goto(`${BASE_URL}${raceUrl}`);
            await page.click('[data-testid="btn-new-horse"]');

            const form = page.locator('[data-testid="horse-form"]');
            await expect(form).toBeVisible();
            await expect(page.locator('[data-testid="input-horse-number"]')).toBeVisible();
            await expect(page.locator('[data-testid="input-horse-name"]')).toBeVisible();
            await expect(page.locator('[data-testid="input-horse-jockey"]')).toBeVisible();
            await expect(form.locator('[data-testid*="status" i]')).toHaveCount(0);
            await expect(form.locator('[name*="status" i]')).toHaveCount(0);
            await expect(form).not.toContainText('Status');
        });

        test('can create a horse, which always starts as Active', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 1);

            await expect(page).toHaveURL(`${BASE_URL}${raceUrl}`);
            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();

            const row = page.locator('[data-testid^="horse-row-"]').last();
            await expect(row).toContainText('Active');
            await expect(row).not.toContainText('Scratched');
        });

        test('scratch checkbox is hidden until the event is published', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 10);

            const row = page.locator('[data-testid^="horse-row-"]').last();
            await expect(row.locator('[data-testid^="checkbox-scratch-"]')).toHaveCount(0);
            await expect(page.locator('[data-testid="btn-save-scratches"]')).toHaveCount(0);
            await expect(page.getByText('Scratch becomes available once the event is published.')).toBeVisible();

            await publishEventFromRacePage(page);
            await page.goto(`${BASE_URL}${raceUrl}`);

            await expect(page.locator('[data-testid^="horse-row-"]').last().locator('[data-testid^="checkbox-scratch-"]')).toBeVisible();
            await expect(page.locator('[data-testid="btn-save-scratches"]')).toBeVisible();
        });

        test('can edit a horse\'s number, name and jockey', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 2);

            const editBtn = page.locator('[data-testid^="btn-edit-horse-"]').last();
            await editBtn.click();

            await page.fill('[data-testid="input-horse-name"]', 'Renamed Horse');
            await page.click('[data-testid="btn-submit"]');

            await expect(page).toHaveURL(`${BASE_URL}${raceUrl}`);
            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
            await expect(page.locator('[data-testid^="horse-row-"]').last()).toContainText('Renamed Horse');
        });

        test('can delete a horse', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 3);

            const deleteBtn = page.locator('[data-testid^="btn-delete-horse-"]').last();
            page.once('dialog', dialog => dialog.accept());
            await deleteBtn.click();

            await expect(page).toHaveURL(`${BASE_URL}${raceUrl}`);
            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
        });

        test('checking scratch and saving flips the horse to Scratched and removes the checkbox', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 4);

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

            await publishEventFromRacePage(page);
            await page.goto(`${BASE_URL}${raceUrl}`);

            await page.check(`[data-testid="checkbox-scratch-${horseId}"]`);
            await page.click('[data-testid="btn-save-scratches"]');

            await expect(page).toHaveURL(`${BASE_URL}${raceUrl}`);
            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();

            const scratchedRow = page.locator(`[data-testid="horse-row-${horseId}"]`);
            await expect(scratchedRow).toContainText('Scratched');
            await expect(scratchedRow.locator(`[data-testid="checkbox-scratch-${horseId}"]`)).toHaveCount(0);
        });

        test('leaving a horse unchecked and saving does not scratch it', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 5);

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

            await publishEventFromRacePage(page);
            await page.goto(`${BASE_URL}${raceUrl}`);

            await page.click('[data-testid="btn-save-scratches"]');

            await expect(page).toHaveURL(`${BASE_URL}${raceUrl}`);
            const stillActiveRow = page.locator(`[data-testid="horse-row-${horseId}"]`);
            await expect(stillActiveRow).toContainText('Active');
            await expect(stillActiveRow.locator(`[data-testid="checkbox-scratch-${horseId}"]`)).toBeVisible();
        });

        test('horse Edit/Delete disappear once the event is published, but Scratch still works', async ({ page }) => {
            const raceUrl = await createEventRaceUrl(page);
            await addHorse(page, raceUrl, 6);

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

            await publishEventFromRacePage(page);
            await page.goto(`${BASE_URL}${raceUrl}`);
            const publishedRow = page.locator(`[data-testid="horse-row-${horseId}"]`);
            await expect(publishedRow.locator(`[data-testid="btn-edit-horse-${horseId}"]`)).toHaveCount(0);
            await expect(publishedRow.locator(`[data-testid="btn-delete-horse-${horseId}"]`)).toHaveCount(0);
            await expect(publishedRow.locator(`[data-testid="checkbox-scratch-${horseId}"]`)).toBeVisible();

            await page.check(`[data-testid="checkbox-scratch-${horseId}"]`);
            await page.click('[data-testid="btn-save-scratches"]');

            await expect(page.locator(`[data-testid="horse-row-${horseId}"]`)).toContainText('Scratched');
        });

    });

});
