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

// Exercises the wallet-credit audit trail written during Live Racing
// settlement: every settled bet (won / void / lost) must produce a
// live_racing_settlement row, and won/void must also produce a
// wallet_transaction row. Setup mirrors event_race_settlement.spec.ts.

async function createArena(page: Page, betTypeKey: string, amount: string): Promise<string> {
    const name = `Credit Arena ${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
    const fieldTestId = 'input-' + betTypeKey.replace(/_/g, '-') + '-amount';

    await page.goto(`${BASE_URL}/wfbo/managements/new`);
    await page.fill('[data-testid="input-name"]', name);
    await page.fill(`[data-testid="${fieldTestId}"]`, amount);
    await page.click('[data-testid="btn-submit"]');
    await expect(page).toHaveURL(`${BASE_URL}/wfbo/managements`);

    return name;
}

async function createEventShowUrl(page: Page, arenaName: string): Promise<string> {
    const dateStr = uniqueFutureDate();
    await page.goto(`${BASE_URL}/wfbo/events/new`);
    await page.selectOption('[data-testid="select-event-management"]', { label: arenaName });
    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');
    return eventHref ?? '';
}

async function addRace(page: Page, eventUrl: string, raceNumber: number): Promise<string> {
    await page.goto(`${BASE_URL}${eventUrl}`);
    await page.click('[data-testid="btn-new-race"]');
    await page.fill('[data-testid="input-race-number"]', String(raceNumber));
    await page.click('[data-testid="btn-submit"]');

    const row = page.locator('[data-testid^="race-row-"]').filter({ hasText: String(raceNumber) });
    const raceHref = await row.locator('[data-testid^="btn-view-race-"]').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 offerSingleBetType(page: Page, eventUrl: string, key: string, raceId: string): Promise<void> {
    await page.goto(`${BASE_URL}${eventUrl}?tab=bet-types`);
    await page.check(`[data-testid="checkbox-leg-${key}-${raceId}"]`);
    await page.click('[data-testid="btn-save-bet-types"]');
    await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
}

async function publishEvent(page: Page, eventUrl: string): Promise<void> {
    await page.goto(`${BASE_URL}${eventUrl}`);
    page.once('dialog', dialog => dialog.accept());
    await page.click('[data-testid="btn-publish-event"]');
}

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();
}

async function dividendRowId(page: Page, label: string): Promise<string> {
    const row = page.locator('[data-testid^="dividend-row-"]').filter({ hasText: label });
    const testId = await row.getAttribute('data-testid');
    return testId?.replace('dividend-row-', '') ?? '';
}

async function betTypeCardId(page: Page, label: string): Promise<string> {
    const tab = page.locator('.wizard-key-tab').filter({ hasText: label });
    const key = await tab.getAttribute('data-key');
    const radio = page.locator(`.wizard-key-panel[data-key="${key}"] .wizard-bet-radio`).first();
    return (await radio.getAttribute('value')) ?? '';
}

async function wizardPickBet(page: Page, cardId: string): Promise<void> {
    const key = await page.locator(`[data-testid="bet-panel-${cardId}"]`).getAttribute('data-key');
    await page.click(`[data-testid="tab-bet-key-${key}"]`);
}

async function placeWinBet(page: Page, eventId: string, horseId: string, amount = '10.00'): Promise<void> {
    await page.goto(`${BASE_URL}/play/live-racing/${eventId}`);
    const cardId = await betTypeCardId(page, 'Win');
    await wizardPickBet(page, cardId);
    await page.check(`[data-testid="checkbox-pos-1-horse-${horseId}-bet-${cardId}"]`);
    await page.fill('[data-testid="input-wizard-amount"]', amount);
    await page.click('[data-testid="btn-wizard-submit"]');
    await expect(page.locator('[data-testid="wizard-step-2"]')).toBeVisible();
}

async function scaffoldWinEvent(page: Page): Promise<{ eventUrl: string; eventId: string; raceUrl: string; raceId: string; horse1: string; horse2: string }> {
    const arenaName = await createArena(page, 'win', '10.00');
    const eventUrl  = await createEventShowUrl(page, arenaName);
    const eventId   = eventUrl.split('/').pop() ?? '';
    const raceUrl   = await addRace(page, eventUrl, 1);
    const raceId    = raceUrl.split('/').pop() ?? '';
    const horse1    = await addHorse(page, raceUrl, 1);
    const horse2    = await addHorse(page, raceUrl, 2);

    await offerSingleBetType(page, eventUrl, 'win', raceId);
    await publishEvent(page, eventUrl);
    await ensureLiveRacingEnabled(page);

    return { eventUrl, eventId, raceUrl, raceId, horse1, horse2 };
}

test.describe('WFBO Live Racing Settlement Credit Audit', () => {

    test('a won bet produces a successful settlement row for the payout', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        const { eventId, raceUrl, horse1, horse2 } = await scaffoldWinEvent(page);

        await loginAs(page, USER.mobile, USER.password);
        await placeWinBet(page, eventId, horse1); // backs the eventual winner

        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await closeBetting(page, raceUrl);
        const winId = await dividendRowId(page, 'Win');
        await page.selectOption('[data-testid="select-finisher-1"]', horse1);
        await page.selectOption('[data-testid="select-finisher-2"]', horse2);
        await page.fill(`[data-testid="input-dividend-${winId}"]`, '5.00');
        page.once('dialog', dialog => dialog.accept());
        await page.click('[data-testid="btn-save-result"]');
        await expect(page.locator('[data-testid="settlement-text"]')).toContainText('1 won', { timeout: 20000 });

        await page.goto(`${BASE_URL}/wfbo/events/${eventId}/settlements`);
        const row = page.locator('[data-testid^="settlement-row-"]').first();
        await expect(row).toBeVisible();
        const id = (await row.getAttribute('data-testid'))?.replace('settlement-row-', '') ?? '';
        await expect(page.locator(`[data-testid="settlement-outcome-${id}"]`)).toContainText('Won');
        await expect(page.locator(`[data-testid="settlement-credit-status-${id}"]`)).toContainText('Success');
        await expect(page.locator(`[data-testid="settlement-amount-${id}"]`)).toContainText('5.00'); // 1 ticket x 5.00 dividend
        await expect(page.locator('[data-testid="settlement-failed-banner"]')).toHaveCount(0);
    });

    test('a voided bet produces a successful settlement row and a refund wallet transaction', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        const { eventId, raceUrl, horse1, horse2 } = await scaffoldWinEvent(page);

        await loginAs(page, USER.mobile, USER.password);
        await placeWinBet(page, eventId, horse1);

        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await closeBetting(page, raceUrl);
        const winId = await dividendRowId(page, 'Win');
        await page.selectOption('[data-testid="select-finisher-1"]', horse1);
        await page.selectOption('[data-testid="select-finisher-2"]', horse2);
        await page.check(`[data-testid="checkbox-refund-${winId}"]`); // refund => void every Win bet on this race
        page.once('dialog', dialog => dialog.accept());
        await page.click('[data-testid="btn-save-result"]');
        await expect(page.locator('[data-testid="settlement-text"]')).toContainText('1 void', { timeout: 20000 });

        await page.goto(`${BASE_URL}/wfbo/events/${eventId}/settlements`);
        const row = page.locator('[data-testid^="settlement-row-"]').first();
        const id = (await row.getAttribute('data-testid'))?.replace('settlement-row-', '') ?? '';
        await expect(page.locator(`[data-testid="settlement-outcome-${id}"]`)).toContainText('Void');
        await expect(page.locator(`[data-testid="settlement-credit-status-${id}"]`)).toContainText('Success');
    });

    test('a lost bet produces a settlement row with no wallet movement', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        const { eventId, raceUrl, horse1, horse2 } = await scaffoldWinEvent(page);

        await loginAs(page, USER.mobile, USER.password);
        await placeWinBet(page, eventId, horse2); // backs the loser

        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await closeBetting(page, raceUrl);
        const winId = await dividendRowId(page, 'Win');
        await page.selectOption('[data-testid="select-finisher-1"]', horse1);
        await page.selectOption('[data-testid="select-finisher-2"]', horse2);
        await page.fill(`[data-testid="input-dividend-${winId}"]`, '5.00');
        page.once('dialog', dialog => dialog.accept());
        await page.click('[data-testid="btn-save-result"]');
        await expect(page.locator('[data-testid="settlement-text"]')).toContainText('1 lost', { timeout: 20000 });

        await page.goto(`${BASE_URL}/wfbo/events/${eventId}/settlements`);
        const row = page.locator('[data-testid^="settlement-row-"]').first();
        const id = (await row.getAttribute('data-testid'))?.replace('settlement-row-', '') ?? '';
        await expect(page.locator(`[data-testid="settlement-outcome-${id}"]`)).toContainText('Lost');
        await expect(page.locator(`[data-testid="settlement-credit-status-${id}"]`)).toContainText('Success');
        await expect(page.locator(`[data-testid="settlement-amount-${id}"]`)).toContainText('0.00');
    });

});
