import { test, expect, Page } from '@playwright/test';
import {
    BASE_URL, ADMIN, SUPER_ADMIN, loginAs, registerAndLogin, adjustWalletAsAuditor,
    ensureMinesEnabled, playMinesRound, readWalletBalance,
} from '../helpers';

// Administration ▸ Cashback Campaigns (ROLE_SUPER_ADMIN): X% back on a
// player's net loss (stakes - payouts, settled bets) on the chosen games,
// for bets placed on the campaign's dates / days / daily window. Paid out by
// a super admin once the campaign has ended.

function manilaToday(): string {
    return new Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Manila' }).format(new Date());
}

async function createCampaign(page: Page, name: string, pct: string): Promise<string> {
    await page.goto(`${BASE_URL}/wfbo/cashback-campaigns/new`);
    await page.fill('[data-testid="input-cb-name"]', name);
    await page.fill('[data-testid="input-cb-start-date"]', manilaToday());
    await page.fill('[data-testid="input-cb-end-date"]', manilaToday());
    // Defaults: 12:00 AM – 12:00 AM (whole day), every day, all games.
    await page.click('[data-testid="cb-games-none"]');
    await page.check('[data-testid="input-cb-game-mines"]');
    await page.fill('[data-testid="input-cb-percentage"]', pct);
    await page.click('[data-testid="btn-submit-cashback-campaign"]');

    await expect(page).toHaveURL(/\/wfbo\/cashback-campaigns$/);
    const row = page.locator('[data-testid^="cashback-campaign-row-"]', { hasText: name });
    await expect(row).toBeVisible();
    return ((await row.getAttribute('data-testid')) ?? '').replace('cashback-campaign-row-', '');
}

test.describe('WFBO Cashback Campaigns', () => {
    // The release test plays Mines until the player is down, twice - a random length.
    test.setTimeout(180_000);

    /** Plays Mines as the logged-in player until they're down vs $from; returns the new balance. */
    async function loseAtMines(page: Page, from: number): Promise<number> {
        let balance = from;
        for (let i = 0; i < 15 && balance >= from; i++) {
            expect(await playMinesRound(page)).toBe(true);
            await page.goto(`${BASE_URL}/`);
            balance = await readWalletBalance(page);
        }
        expect(balance).toBeLessThan(from);
        return balance;
    }

    const peso = (n: number) => `₱${n.toFixed(2)}`;
    const round2 = (n: number) => Math.round(n * 100) / 100;

    test('releases mid-campaign pay the loss so far, then counting resets; a final release closes it', async ({ page }, testInfo) => {
        page.on('dialog', (d) => d.accept().catch(() => {}));

        const player = await registerAndLogin(page);
        await adjustWalletAsAuditor(page, player.mobile, '300', 'Cashback e2e funds');
        await ensureMinesEnabled(page);

        await loginAs(page, SUPER_ADMIN.mobile, SUPER_ADMIN.password);
        const name = `Cash Back ${Date.now()}`;
        const id   = await createCampaign(page, name, '10');
        await expect(page.locator(`[data-testid="cashback-campaign-status-${id}"]`)).toHaveText(/running/i);

        // ── Period 1: lose, then release while the campaign is still running ──
        await loginAs(page, player.mobile, player.password);
        await page.goto(`${BASE_URL}/`);
        const start1 = await readWalletBalance(page);
        const end1   = await loseAtMines(page, start1);
        const loss1  = round2(start1 - end1);
        const cb1    = round2(loss1 * 0.1);

        await loginAs(page, SUPER_ADMIN.mobile, SUPER_ADMIN.password);
        await page.goto(`${BASE_URL}/wfbo/cashback-campaigns`);
        await page.click(`[data-testid="btn-review-cashback-campaign-${id}"]`);
        await expect(page.locator('[data-testid="cashback-no-releases"]')).toBeVisible();
        const row = page.locator('[data-testid^="cashback-row-"]', { hasText: player.mobile });
        const userId = ((await row.getAttribute('data-testid')) ?? '').replace('cashback-row-', '');
        await expect(page.locator(`[data-testid="cashback-loss-${userId}"]`)).toHaveText(peso(loss1));
        await expect(page.locator(`[data-testid="cashback-amount-${userId}"]`)).toHaveText(peso(cb1));

        await expect(page.locator('[data-testid="btn-pay-out-cashback"]')).toHaveText('Release payout now');
        await page.click('[data-testid="btn-pay-out-cashback"]');
        await expect(page.locator('[data-testid="flash-success"]').filter({ hasText: 'Counting starts again from now' }).first()).toBeVisible();
        await expect(page.locator('[data-testid="cashback-release-1"]')).toBeVisible();
        // Counting restarted: the player isn't in the open period any more.
        await expect(page.locator(`[data-testid="cashback-row-${userId}"]`)).toHaveCount(0);

        await page.goto(`${BASE_URL}/wfbo/cashback-campaigns`);
        await expect(page.locator(`[data-testid="cashback-campaign-status-${id}"]`)).toHaveText(/running/i);   // still running
        await expect(page.locator(`[data-testid="cashback-campaign-paid-${id}"]`)).toContainText('1 release');

        // Rules are locked now; the name can still change.
        await page.click(`[data-testid="btn-edit-cashback-campaign-${id}"]`);
        await expect(page.locator('[data-testid="cb-locked-note"]')).toBeVisible();
        await expect(page.locator('[data-testid="input-cb-percentage"]')).toBeDisabled();

        // ── Period 2: lose again - only this new loss counts ──
        await loginAs(page, player.mobile, player.password);
        await page.goto(`${BASE_URL}/`);
        const start2 = await readWalletBalance(page);
        expect(start2).toBeCloseTo(end1 + cb1, 2);                 // release #1 credited
        const end2  = await loseAtMines(page, start2);
        const loss2 = round2(start2 - end2);
        const cb2   = round2(loss2 * 0.1);

        await loginAs(page, SUPER_ADMIN.mobile, SUPER_ADMIN.password);
        await page.goto(`${BASE_URL}/wfbo/cashback-campaigns/${id}/payout`);
        await expect(page.locator(`[data-testid="cashback-loss-${userId}"]`)).toHaveText(peso(loss2));

        // End it now → the next release is the final one and closes the campaign.
        await page.goto(`${BASE_URL}/wfbo/cashback-campaigns`);
        await page.click(`[data-testid="btn-end-cashback-campaign-${id}"]`);
        await expect(page).toHaveURL(new RegExp(`/wfbo/cashback-campaigns/${id}/payout$`));
        await expect(page.locator('[data-testid="cashback-final-note"]')).toBeVisible();
        await expect(page.locator(`[data-testid="cashback-amount-${userId}"]`)).toHaveText(peso(cb2));
        await page.click('[data-testid="btn-pay-out-cashback"]');
        await expect(page.locator('[data-testid="flash-success"]').filter({ hasText: 'final release' }).first()).toBeVisible();
        await expect(page.locator('[data-testid="cashback-paid-summary"]')).toContainText('2 releases');
        await expect(page.locator('[data-testid="btn-pay-out-cashback"]')).toHaveCount(0);
        await expect(page.locator('[data-testid="cashback-release-2"]')).toContainText('Final');
        await page.locator('[data-testid="cashback-release-1"] summary').click();
        await page.screenshot({ path: testInfo.outputPath('cashback-releases.png'), fullPage: true });

        await page.goto(`${BASE_URL}/wfbo/cashback-campaigns`);
        await expect(page.locator(`[data-testid="cashback-campaign-status-${id}"]`)).toHaveText(/paid/i);

        // The player got both cashbacks, as Bonus transactions.
        await loginAs(page, player.mobile, player.password);
        await page.goto(`${BASE_URL}/`);
        expect(await readWalletBalance(page)).toBeCloseTo(end2 + cb2, 2);
        await page.goto(`${BASE_URL}/transactions`);
        await expect(page.locator('body')).toContainText(`Cashback — ${name}`);
    });

    test('validation: at least one game and a percentage up to 100', async ({ page }) => {
        await loginAs(page, SUPER_ADMIN.mobile, SUPER_ADMIN.password);
        await page.goto(`${BASE_URL}/wfbo/cashback-campaigns/new`);
        await page.fill('[data-testid="input-cb-name"]', 'Bad campaign');
        await page.fill('[data-testid="input-cb-start-date"]', manilaToday());
        await page.fill('[data-testid="input-cb-end-date"]', manilaToday());
        await page.click('[data-testid="cb-games-none"]');
        await page.fill('[data-testid="input-cb-percentage"]', '150');
        await page.click('[data-testid="btn-submit-cashback-campaign"]');

        await expect(page.locator('[data-testid="flash-error"]').filter({ hasText: 'Select at least one game.' }).first()).toBeVisible();
        await expect(page.locator('[data-testid="flash-error"]').filter({ hasText: 'at most 100' }).first()).toBeVisible();
    });

    test('sidebar Campaigns group holds the campaign pages and Bonuses, for super admins only', async ({ page }) => {
        await loginAs(page, SUPER_ADMIN.mobile, SUPER_ADMIN.password);
        await page.goto(`${BASE_URL}/wfbo`);
        const group = page.locator('#campaigns-group-body');
        await expect(group).toHaveClass(/is-collapsed/);
        await page.click('[data-testid="wfbo-nav-campaigns-group"]');
        await expect(group.locator('[data-testid="wfbo-nav-deposit-campaigns"]')).toBeVisible();
        await expect(group.locator('[data-testid="wfbo-nav-bonuses"]')).toBeVisible();
        await group.locator('[data-testid="wfbo-nav-cashback-campaigns"]').click();
        await expect(page).toHaveURL(/\/wfbo\/cashback-campaigns$/);
        // Open (and highlighted) on a campaign page; no longer under Administration.
        await expect(group).not.toHaveClass(/is-collapsed/);
        await expect(page.locator('#admin-group-body [data-testid^="wfbo-nav-"][data-testid$="-campaigns"], #admin-group-body [data-testid="wfbo-nav-bonuses"]')).toHaveCount(0);
    });

    test('a plain ADMIN cannot open Cashback Campaigns', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await page.goto(`${BASE_URL}/wfbo`);
        await expect(page.locator('[data-testid="wfbo-nav-campaigns-group"]')).toHaveCount(0);
        await expect(page.locator('[data-testid="wfbo-nav-cashback-campaigns"]')).toHaveCount(0);
        const res = await page.goto(`${BASE_URL}/wfbo/cashback-campaigns`);
        expect(res?.status()).toBe(403);
    });
});
