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

// Fixture agents (src/DataFixtures/AppFixtures.php)
const MASTER_AGENT_REF = 'ABCDEF01';   // "Agent User", ROLE_MASTER_AGENT
const AGENT2_REF       = 'AGENT2REF';  // "Agent2 User", ROLE_AGENT
const AGENT2_LABEL     = /Agent2 User/;

/** Disables every enabled announcement so each test starts from a clean slate (the DB is shared across retries). */
async function disableAllAnnouncements(page: Page): Promise<void> {
    await page.goto(`${BASE_URL}/wfbo/announcements`);
    page.on('dialog', (d) => d.accept());
    for (;;) {
        const disable = page.locator('[data-testid^="btn-toggle-"]', { hasText: 'Disable' }).first();
        if (await disable.count() === 0) {
            break;
        }
        await disable.click();
        await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
    }
}

async function createAnnouncement(
    page: Page,
    opts: { message: string; agentLabel?: RegExp },
): Promise<void> {
    await page.goto(`${BASE_URL}/wfbo/announcements/new`);
    await page.fill('[data-testid="input-message"]', opts.message);
    if (opts.agentLabel) {
        await page.check('[data-testid="input-audience-agents"]');
        await expect(page.locator('[data-testid="agent-picker"]')).toBeVisible();
        await page.fill('[data-testid="input-agent-filter"]', 'agent2');
        await page.getByLabel(opts.agentLabel).check();
    } else {
        await page.check('[data-testid="input-audience-all"]');
    }
    await page.click('[data-testid="btn-submit"]');
}

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

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

        test('finance-only user cannot access announcements', async ({ page }) => {
            await loginAs(page, FINANCE.mobile, FINANCE.password);
            await page.goto(`${BASE_URL}/wfbo/announcements`);

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

        test('player cannot access announcements admin', async ({ page }) => {
            await loginAs(page, USER.mobile, USER.password);
            await page.goto(`${BASE_URL}/wfbo/announcements`);

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

    });

    test.describe.serial('publishing and targeting', () => {

        test('all-players announcement shows under the navbar with a clickable link', async ({ page }) => {
            await loginAs(page, ADMIN.mobile, ADMIN.password);
            await disableAllAnnouncements(page);

            await page.click('[data-testid="btn-new-announcement"]');
            await createAnnouncement(page, {
                message: 'Maintenance tonight at 11 PM. [Read more](https://example.com/notice)',
            });
            await expect(page.locator('[data-testid="flash-success"]')).toContainText('Announcement published.');

            // Not shown inside WFBO (the navbar block is overridden there)
            await expect(page.locator('[data-testid="announcement-bar"]')).toHaveCount(0);

            await loginAs(page, USER.mobile, USER.password);
            await page.goto(`${BASE_URL}/`);
            const bar = page.locator('[data-testid="announcement-bar"]');
            await expect(bar).toHaveCount(1);
            await expect(bar).toContainText('Maintenance tonight at 11 PM.');
            await expect(bar).toHaveClass(/announcement-bar--all/);
            await expect(bar).toHaveCSS('text-align', 'center');

            const link = bar.getByRole('link', { name: 'Read more' });
            await expect(link).toHaveAttribute('href', 'https://example.com/notice');
            await expect(link).toHaveAttribute('target', '_blank');

            // Dismissing hides it for this page view only - a refresh shows it again
            await bar.locator('[data-testid="announcement-dismiss"]').click();
            await expect(bar).toHaveCount(0);
            await page.reload();
            await expect(bar).toHaveCount(1);
            await expect(bar).toContainText('Maintenance tonight at 11 PM.');
        });

        test('a second all-players announcement is rejected while one is enabled', async ({ page }) => {
            await loginAs(page, ADMIN.mobile, ADMIN.password);
            await createAnnouncement(page, { message: 'Second global announcement' });

            await expect(page.locator('[data-testid="flash-error"]')).toContainText('already enabled for all players');
        });

        test('agent-targeted announcement shows only to that agent\'s direct players', async ({ page }) => {
            await loginAs(page, ADMIN.mobile, ADMIN.password);
            await createAnnouncement(page, {
                message: 'Agent2 players: bonus weekend! https://example.com/promo',
                agentLabel: AGENT2_LABEL,
            });
            await expect(page.locator('[data-testid="flash-success"]')).toContainText('Announcement published.');

            // Direct player of Agent2 sees the targeted bar first, then the global one
            await registerUserWithReferralCode(page, AGENT2_REF);
            await page.goto(`${BASE_URL}/`);
            const bars = page.locator('[data-testid="announcement-bar"]');
            await expect(bars).toHaveCount(2);
            await expect(bars.nth(0)).toContainText('Agent2 players: bonus weekend!');
            await expect(bars.nth(0)).toHaveClass(/announcement-bar--agents/);
            await expect(bars.nth(0).getByRole('link', { name: 'https://example.com/promo' })).toHaveClass(/announcement-link/);
            await expect(bars.nth(1)).toHaveClass(/announcement-bar--all/);
            await expect(bars.nth(1)).toContainText('Maintenance tonight');

            // Mobile: a message too long for one line scrolls as a ticker
            await page.setViewportSize({ width: 390, height: 800 });
            await page.reload();
            await expect(bars.nth(0)).toHaveClass(/is-ticker/);
            await expect(bars.nth(0).locator('.announcement-bar__text')).toHaveCSS('animation-name', 'announcement-ticker');
            await expect(bars.nth(0).locator('.announcement-bar__text')).toHaveCSS('white-space', 'nowrap');
            await page.setViewportSize({ width: 1280, height: 720 });
            await page.reload();
            await expect(bars.nth(0)).not.toHaveClass(/is-ticker/);

            // A player under a different agent only sees the global bar
            await registerUserWithReferralCode(page, MASTER_AGENT_REF);
            await page.goto(`${BASE_URL}/`);
            await expect(bars).toHaveCount(1);
            await expect(bars.first()).toContainText('Maintenance tonight');
        });

        test('only one enabled announcement per agent - disable first, then publish a new one', async ({ page }) => {
            await loginAs(page, ADMIN.mobile, ADMIN.password);

            await createAnnouncement(page, { message: 'Replacement for Agent2', agentLabel: AGENT2_LABEL });
            await expect(page.locator('[data-testid="flash-error"]')).toContainText('already enabled for Agent2 User');

            // Disable the existing Agent2 announcement
            await page.goto(`${BASE_URL}/wfbo/announcements`);
            page.on('dialog', (d) => d.accept());
            const row = page.locator('[data-testid^="announcement-row-"]', { hasText: 'Agent2 players: bonus weekend!' });
            await row.locator('[data-testid^="btn-toggle-"]').click();
            await expect(page.locator('[data-testid="flash-success"]')).toContainText('Announcement disabled.');

            await createAnnouncement(page, { message: 'Replacement for Agent2', agentLabel: AGENT2_LABEL });
            await expect(page.locator('[data-testid="flash-success"]')).toContainText('Announcement published.');

            // Re-enabling the old one now conflicts with the replacement
            await row.locator('[data-testid^="btn-toggle-"]').click();
            await expect(page.locator('[data-testid="flash-error"]')).toContainText('already enabled for Agent2 User');

            await registerUserWithReferralCode(page, AGENT2_REF);
            await page.goto(`${BASE_URL}/`);
            await expect(page.locator('[data-testid="announcement-bar"]').first()).toContainText('Replacement for Agent2');
        });

    });

});
