import { test, expect } from '@playwright/test';
import {
    BASE_URL, ADMIN, AGENT, USER, loginAs, uniqueFutureDate,
    createArena, createEventShowUrl, addRace, addHorse,
    offerMultiBetTypeCombos, publishEvent, ensureLiveRacingEnabled,
    closeBetting, saveResult, settleAndMarkRace, placeWizardBet,
} 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 createEvent(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 href = await row.locator('[data-testid^="btn-view-"]').getAttribute('href');
    return href ?? '';
}

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

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

        test('admin can view an event detail page', async ({ page }) => {
            await loginAs(page, ADMIN.mobile, ADMIN.password);
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);

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

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

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

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

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

    });

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

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

        test('new race form has race number field but no status field', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');

            const form = page.locator('[data-testid="race-form"]');
            await expect(form).toBeVisible();
            await expect(page.locator('[data-testid="input-race-number"]')).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('Races tab drops the bet-amount columns; the Report tab carries them with a totals row', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');
            await page.fill('[data-testid="input-race-number"]', '1');
            await page.click('[data-testid="btn-submit"]');

            const racesTable = page.locator('[data-testid="races-table"]');
            await expect(racesTable).toBeVisible();
            await expect(racesTable.locator('th', { hasText: 'Bet Amount' })).toHaveCount(0);
            await expect(racesTable.locator('th', { hasText: 'Revenue' })).toHaveCount(0);

            await page.click('[data-testid="tab-report"]');
            const reportTable = page.locator('[data-testid="report-table"]');
            await expect(reportTable).toBeVisible();
            await expect(reportTable.locator('th', { hasText: 'Bet Amount' })).toBeVisible();
            await expect(reportTable.locator('th', { hasText: 'Commission' })).toBeVisible();
            await expect(page.locator('[data-testid="report-combo-note"]')).toBeVisible();
            await expect(page.locator('[data-testid^="report-row-"]')).toHaveCount(1);
            await expect(page.locator('[data-testid="report-totals-row"]')).toBeVisible();
            await expect(page.locator('[data-testid="report-total-bet-amount"]')).toContainText('₱0.00');
            await expect(page.locator('[data-testid="report-total-commission"]')).toContainText('₱0.00');
            await expect(page.locator('[data-testid="report-total-revenue"]')).toContainText('₱0.00');
        });

        test('Report tab attributes a multi-race bet to its last leg only, not every leg', async ({ page }) => {
            test.setTimeout(120_000);

            const arenaName = await createArena(page, 'ReportDD', { daily_double: '10' });
            const created   = await createEventShowUrl(page, arenaName);
            // Both races are created before any horses are added - adding
            // horses to race 1 first would make its row's horse-count text
            // collide with addRace(..., 2)'s "hasText: '2'" race-number filter.
            const race1     = await addRace(page, created.eventUrl, 1);
            const race2     = await addRace(page, created.eventUrl, 2);
            const h1        = await addHorse(page, race1.raceUrl, 1);
            await addHorse(page, race1.raceUrl, 2);
            const h2        = await addHorse(page, race2.raceUrl, 1);
            await addHorse(page, race2.raceUrl, 2);

            await offerMultiBetTypeCombos(page, created.eventUrl, 'daily_double', [[race1.raceId, race2.raceId]]);
            await publishEvent(page, created.eventUrl);
            await ensureLiveRacingEnabled(page);

            await loginAs(page, USER.mobile, USER.password);
            await placeWizardBet(page, {
                eventId: created.eventId,
                raceId: race1.raceId,
                cardLabel: /^Daily Double$/,
                legs: { [race1.raceId]: [h1], [race2.raceId]: [h2] },
            });

            // Race 1 (first leg) has no Daily Double combo block - its result
            // saves empty. Race 2 (last leg) is where the whole combo's
            // winning horses + dividend are entered.
            await loginAs(page, ADMIN.mobile, ADMIN.password);
            await closeBetting(page, race1.raceUrl);
            await page.goto(`${BASE_URL}${race1.raceUrl}`);
            await expect(page.locator('[data-testid^="combo-bettype-"]').filter({ hasText: 'Daily Double' })).toHaveCount(0);
            page.once('dialog', dialog => dialog.accept());
            await page.click('[data-testid="btn-save-result"]');
            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();

            await closeBetting(page, race2.raceUrl);
            await page.goto(`${BASE_URL}${race2.raceUrl}`);
            const comboBlock = page.locator('[data-testid^="combo-bettype-"]').filter({ hasText: 'Daily Double' });
            const eventBetTypeId = (await comboBlock.getAttribute('data-testid'))?.replace('combo-bettype-', '') ?? '';
            await saveResult(page, race2.raceUrl, {
                combinations: { [eventBetTypeId]: [{ horseIds: [h1, h2], dividend: '20.00' }] },
            });

            await settleAndMarkRace(page, race1.raceId);
            await settleAndMarkRace(page, race2.raceId);

            await page.goto(`${BASE_URL}${created.eventUrl}?tab=report`);
            await expect(page.locator(`[data-testid="report-bet-count-${race1.raceId}"]`)).toHaveText('0');
            await expect(page.locator(`[data-testid="report-bet-count-${race2.raceId}"]`)).toHaveText('1');
            await expect(page.locator(`[data-testid="report-bet-amount-${race1.raceId}"]`)).toHaveText('₱0.00');
            await expect(page.locator(`[data-testid="report-bet-amount-${race2.raceId}"]`)).toHaveText('₱10.00');

            // The bet's stake landed on exactly one race (its last leg), so the
            // per-race sum matches the Total - no fan-out double-counting.
            await expect(page.locator('[data-testid="report-total-bet-count"]')).toHaveText('1');
            await expect(page.locator('[data-testid="report-total-bet-amount"]')).toHaveText('₱10.00');
        });

        test('can create a race, which always starts as Open', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');

            await page.fill('[data-testid="input-race-number"]', '1');
            await page.click('[data-testid="btn-submit"]');

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

            const row = page.locator('[data-testid^="race-row-"]').last();
            await expect(row).toContainText('Open');
            await expect(row).not.toContainText('Closed');
            await expect(row.locator('[data-testid^="btn-delete-race-"]')).toBeVisible();
        });

        test('view race page has a Close Betting button that closes betting after confirmation', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');
            await page.fill('[data-testid="input-race-number"]', '2');
            await page.click('[data-testid="btn-submit"]');

            const viewBtn = page.locator('[data-testid^="btn-view-race-"]').last();
            await viewBtn.click();

            await expect(page.locator('[data-testid="race-status"]')).toHaveText('Open');
            await expect(page.locator('[data-testid="btn-close-betting"]')).toBeVisible();

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

            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
            await expect(page.locator('[data-testid="race-status"]')).toHaveText('Closed');
            await expect(page.locator('[data-testid="btn-close-betting"]')).toHaveCount(0);
        });

        test('delete button disappears from the event page once a race is closed', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');
            await page.fill('[data-testid="input-race-number"]', '3');
            await page.click('[data-testid="btn-submit"]');

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

            await page.click(`[data-testid="btn-view-race-${raceId}"]`);
            page.once('dialog', dialog => dialog.accept());
            await page.click('[data-testid="btn-close-betting"]');

            await page.goto(`${BASE_URL}${eventUrl}`);
            const closedRow = page.locator(`[data-testid="race-row-${raceId}"]`);
            await expect(closedRow).toContainText('Closed');
            await expect(closedRow.locator(`[data-testid="btn-delete-race-${raceId}"]`)).toHaveCount(0);
        });

        test('can delete an open race', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');
            await page.fill('[data-testid="input-race-number"]', '4');
            await page.click('[data-testid="btn-submit"]');

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

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

        test('deleting a race that still has a horse is blocked with a friendly error instead of crashing', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');
            await page.fill('[data-testid="input-race-number"]', '6');
            await page.click('[data-testid="btn-submit"]');

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

            await page.click(`[data-testid="btn-view-race-${raceId}"]`);
            await page.click('[data-testid="btn-new-horse"]');
            await page.fill('[data-testid="input-horse-number"]', '1');
            await page.fill('[data-testid="input-horse-name"]', 'Guard Test Horse');
            await page.fill('[data-testid="input-horse-jockey"]', 'Guard Test Jockey');
            await page.click('[data-testid="btn-submit"]');

            await page.goto(`${BASE_URL}${eventUrl}`);
            page.once('dialog', dialog => dialog.accept());
            await page.click(`[data-testid="btn-delete-race-${raceId}"]`);

            await expect(page.locator('[data-testid="flash-error"]')).toBeVisible();
            await expect(page.locator('[data-testid="flash-error"]')).toContainText('horses');

            await expect(page.locator(`[data-testid="race-row-${raceId}"]`)).toHaveCount(1);
        });

        test('race list shows the total number of horses enrolled in each race', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');
            await page.fill('[data-testid="input-race-number"]', '7');
            await page.click('[data-testid="btn-submit"]');

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

            // No horses yet.
            await expect(page.locator(`[data-testid="race-horse-count-${raceId}"]`)).toHaveText('0');

            // Add a horse, then revisit the event to confirm the count updates.
            await page.click(`[data-testid="btn-view-race-${raceId}"]`);
            await page.click('[data-testid="btn-new-horse"]');
            await page.fill('[data-testid="input-horse-number"]', '1');
            await page.fill('[data-testid="input-horse-name"]', 'Horse One');
            await page.fill('[data-testid="input-horse-jockey"]', 'Jockey One');
            await page.click('[data-testid="btn-submit"]');

            await page.goto(`${BASE_URL}${eventUrl}`);
            await expect(page.locator(`[data-testid="race-horse-count-${raceId}"]`)).toHaveText('1');
        });

        test('race Delete button disappears once the event is published', async ({ page }) => {
            const eventUrl = await createEvent(page);
            await page.goto(`${BASE_URL}${eventUrl}`);
            await page.click('[data-testid="btn-new-race"]');
            await page.fill('[data-testid="input-race-number"]', '5');
            await page.click('[data-testid="btn-submit"]');

            const row = page.locator('[data-testid^="race-row-"]').last();
            const raceId = (await row.getAttribute('data-testid'))?.replace('race-row-', '');
            await expect(row.locator(`[data-testid="btn-delete-race-${raceId}"]`)).toBeVisible();

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

            const publishedRow = page.locator(`[data-testid="race-row-${raceId}"]`);
            await expect(publishedRow.locator(`[data-testid="btn-delete-race-${raceId}"]`)).toHaveCount(0);
        });

    });

});
