import { test, expect } from '@playwright/test';
import {
    BASE_URL, USER, AGENT, ADMIN, loginAs,
    registerUserWithReferralCode, adjustWalletAsAuditor, ensureLiveRacingEnabled,
    createArena, createEventShowUrl, addRace, addHorses, offerSingleBetTypes,
    publishEvent, placeWizardBet,
} from '../helpers';

// AppFixtures seeds four players referred by AGENT (+10000000002), all with
// last name "Referral" so `?search=Referral` isolates them from players other
// specs register under the same referral code on the shared DB. The list is
// sorted by registration date DESC (newest first), so registration order is
// also list order: Recent, Earlier, Weekly, Dormant.
//   Recent Referral  — registered "now" (< 7d) → Newly Registered
//                      · approved deposit today → Active
//   Earlier Referral — registered 10 days ago   · approved deposit 10 days ago → Watch
//                      (+ a ₱500 withdrawal)
//   Weekly Referral  — registered 20 days ago   · approved deposit 8 days ago  → Watch
//   Dormant Referral — registered 30 days ago   · approved deposit 30 days ago → Inactive
//                      (the fixture player is named "Dormant" — the bucket/badge is
//                      "Inactive")

const MONITOR = `${BASE_URL}/agent/player-monitor?scope=direct&search=Referral`;

test.describe('Agent Portal — Player Monitor', () => {

    test('a non-agent USER cannot open the Player Monitor', async ({ page }) => {
        await loginAs(page, USER.mobile, USER.password);
        await page.goto(`${BASE_URL}/agent/player-monitor`);
        await expect(page.locator('[data-testid="agent-player-monitor-title"]')).not.toBeVisible();
    });

    test.describe('as a master agent', () => {
        test.beforeEach(async ({ page }) => {
            await loginAs(page, AGENT.mobile, AGENT.password);
        });

        test('lists players newest-registered-first, with last-load / cash-in / cash-out and bucket badges', async ({ page }) => {
            await page.goto(MONITOR);
            await expect(page.locator('[data-testid="agent-player-monitor-title"]')).toBeVisible();

            const table = page.locator('[data-testid="agent-player-monitor-table"]');
            const cleaned = (await table.locator('tbody tr td:first-child').allInnerTexts())
                .map(n => n.replace(/\s+(Inactive|Watch|New)(\s+(Inactive|Watch|New))*$/, '').trim());
            const iRecent   = cleaned.findIndex(n => n.includes('Recent Referral'));
            const iEarlier  = cleaned.findIndex(n => n.includes('Earlier Referral'));
            const iWeekly   = cleaned.findIndex(n => n.includes('Weekly Referral'));
            const iDormant  = cleaned.findIndex(n => n.includes('Dormant Referral'));
            // Sorted by registration date DESC: Recent, Earlier, Weekly, Dormant.
            expect(iRecent).toBe(0);
            expect(iRecent).toBeLessThan(iEarlier);
            expect(iEarlier).toBeLessThan(iWeekly);
            expect(iWeekly).toBeLessThan(iDormant);

            const recentRow  = table.locator('tbody tr', { hasText: 'Recent Referral' });
            const earlierRow = table.locator('tbody tr', { hasText: 'Earlier Referral' });
            const dormantRow = table.locator('tbody tr', { hasText: 'Dormant Referral' });
            await expect(recentRow.locator('[data-testid^="badge-new-"]')).toBeVisible();
            await expect(recentRow.locator('[data-testid^="badge-inactive-"]')).toHaveCount(0);
            await expect(recentRow.locator('[data-testid^="badge-watch-"]')).toHaveCount(0);
            await expect(earlierRow.locator('[data-testid^="badge-watch-"]')).toBeVisible();
            await expect(earlierRow.locator('[data-testid^="badge-new-"]')).toHaveCount(0);
            await expect(dormantRow.locator('[data-testid^="badge-inactive-"]')).toBeVisible();

            await expect(earlierRow).toContainText('₱500.00'); // cash-out
            await expect(recentRow.locator('[data-testid^="agent-player-monitor-days-"]')).toContainText('d');
        });

        test('the Inactive filter narrows the list to inactive players only', async ({ page }) => {
            await page.goto(`${MONITOR}&filter=inactive`);
            const rows = page.locator('[data-testid="agent-player-monitor-table"] tbody tr.table-row');
            await expect(rows.filter({ hasText: 'Dormant Referral' })).toHaveCount(1);
            await expect(rows.filter({ hasText: 'Recent Referral' })).toHaveCount(0);
        });

        test('the All downlines scope shows the owning agent column', async ({ page }) => {
            // Fixture "Devon Ken" is owned by sub-agent "Sub Ken" (referredBy =
            // sub-agent), so his row must display the sub-agent name. "Sub Ken"
            // itself is an agent, so it never appears as a player row.
            await page.goto(`${BASE_URL}/agent/player-monitor?scope=all&search=Ken`);
            await expect(page.locator('[data-testid="agent-player-monitor-agent-head"]')).toBeVisible();
            const row = page.locator('[data-testid="agent-player-monitor-table"] tbody tr', { hasText: 'Devon Ken' });
            await expect(row.locator('[data-testid^="agent-player-monitor-agent-"]')).toContainText('Sub Ken');

            // The Agent column is specific to the All downlines scope.
            await page.goto(`${BASE_URL}/agent/player-monitor?scope=direct&search=Ken`);
            await expect(page.locator('[data-testid="agent-player-monitor-agent-head"]')).toHaveCount(0);
        });

        test('the Newly Registered filter is the default and isolates recent registrations', async ({ page }) => {
            // No `filter` param at all — 'new' must be selectable and the pill count
            // must reflect it, but the *default* landing filter stays 'all' (only the
            // order changes) per the agreed behavior.
            await page.goto(MONITOR);
            await expect(page.locator('[data-testid="agent-player-monitor-filter-all"]')).toHaveClass(/is-active/);

            await page.goto(`${MONITOR}&filter=new`);
            await expect(page.locator('[data-testid="agent-player-monitor-filter-new"]')).toHaveClass(/is-active/);
            const rows = page.locator('[data-testid="agent-player-monitor-table"] tbody tr.table-row');
            await expect(rows.filter({ hasText: 'Recent Referral' })).toHaveCount(1);
            await expect(rows.filter({ hasText: 'Earlier Referral' })).toHaveCount(0);
            await expect(rows.filter({ hasText: 'Weekly Referral' })).toHaveCount(0);
            await expect(rows.filter({ hasText: 'Dormant Referral' })).toHaveCount(0);
        });

        test('clicking a player opens their read-only deposit/withdrawal detail', async ({ page }) => {
            await page.goto(MONITOR);
            await page.locator('[data-testid="agent-player-monitor-table"] tbody tr', { hasText: 'Earlier Referral' })
                .locator('a').first().click();

            await expect(page.locator('[data-testid="agent-player-detail-title"]')).toContainText('Earlier Referral');
            await expect(page.locator('[data-testid="stat-player-detail-cash-in"]')).toContainText('₱1,500.00');
            await expect(page.locator('[data-testid="stat-player-detail-cash-out"]')).toContainText('₱500.00');
            await expect(page.locator('[data-testid="agent-player-detail-table"] tbody tr')).not.toHaveCount(0);

            await page.click('[data-testid="agent-player-detail-tab-withdrawals"]');
            await expect(page.locator('[data-testid="agent-player-detail-table"]')).toContainText('GCASH');
        });

        test('the Bets tab lists a downline player\'s cross-game bet history with status', async ({ page }) => {
            const player = await registerUserWithReferralCode(page, 'ABCDEF01');
            await adjustWalletAsAuditor(page, player.mobile, '500.00', 'Fund agent bets-tab test');

            await loginAs(page, ADMIN.mobile, ADMIN.password);
            await ensureLiveRacingEnabled(page);
            const arena = await createArena(page, 'AgentBetsTab', { win: '10' });
            const { eventUrl, eventId } = await createEventShowUrl(page, arena);
            const raceNumber = (Date.now() % 900) + 1;
            const race = await addRace(page, eventUrl, raceNumber);
            const horseIds = await addHorses(page, race.raceUrl, 2);
            await offerSingleBetTypes(page, eventUrl, [{ key: 'win', raceId: race.raceId }]);
            await publishEvent(page, eventUrl);

            await loginAs(page, player.mobile, player.password);
            await placeWizardBet(page, {
                eventId, raceId: race.raceId, cardLabel: 'Win',
                positions: { 1: [horseIds[0]] }, amount: '10',
            });

            await loginAs(page, AGENT.mobile, AGENT.password);
            await page.goto(`${BASE_URL}/agent/users?search=${encodeURIComponent(player.mobile)}`);
            await page.locator('[data-testid^="agent-user-row-"]', { hasText: player.mobile })
                .locator('[data-testid^="agent-player-link-"]').click();

            await page.click('[data-testid="agent-player-detail-tab-bets"]');
            const table = page.locator('[data-testid="agent-player-detail-bets-table"]');
            await expect(table).toBeVisible();
            await expect(table).toContainText('Live Racing');
            await expect(table).toContainText('₱10.00');
            await expect(table.locator('.badge-status--neutral')).toContainText('Pending');
            // Detail column shows the bet type plus the per-leg horse-number
            // breakdown ("Win — R{n}: 1"), matching the WFBO admin reference
            // page's own Detail rendering, not just the flat Date/Game/Amount
            // summary the tab shipped with before this change.
            await expect(table).toContainText('Win');
            await expect(table).toContainText(`R${raceNumber}: 1`);
        });

        test('the Bets/Deposits/Withdrawals tables stack into label/value rows on mobile', async ({ page }) => {
            const player = await registerUserWithReferralCode(page, 'ABCDEF01');

            await loginAs(page, AGENT.mobile, AGENT.password);
            await page.goto(`${BASE_URL}/agent/users?search=${encodeURIComponent(player.mobile)}`);
            await page.locator('[data-testid^="agent-user-row-"]', { hasText: player.mobile })
                .locator('[data-testid^="agent-player-link-"]').click();

            await page.setViewportSize({ width: 375, height: 800 });

            // The global .stack-table CSS only hides <thead> at <=480px width -
            // asserting it's hidden here confirms the responsive rule actually
            // applies, not just that the class is present in the markup.
            await expect(page.locator('[data-testid="agent-player-detail-table"] thead')).toBeHidden();

            await page.click('[data-testid="agent-player-detail-tab-bets"]');
            await expect(page.locator('[data-testid="agent-player-detail-bets-table"] thead')).toBeHidden();
        });

        test('a player outside the agent\'s downline is 404', async ({ page }) => {
            const res = await page.goto(`${BASE_URL}/agent/players/999999`);
            expect(res?.status()).toBe(404);
        });

        test('the My Referrals list links each player name to the drill-down', async ({ page }) => {
            await page.goto(`${BASE_URL}/agent/users?search=Referral`);
            const row = page.locator('[data-testid^="agent-user-row-"]', { hasText: 'Earlier Referral' });
            const link = row.locator('[data-testid^="agent-player-link-"]');
            await expect(link).toBeVisible();

            await link.click();
            await expect(page.locator('[data-testid="agent-player-detail-title"]')).toContainText('Earlier Referral');
            await expect(page.locator('[data-testid="stat-player-detail-cash-in"]')).toContainText('₱1,500.00');
        });

        test('the Insight Player Activity list links each player name to the drill-down', async ({ page }) => {
            await page.goto(`${BASE_URL}/agent/insight`);
            const row = page.locator('[data-testid^="agent-insight-player-activity-row-"]', { hasText: 'Recent Referral' });
            const link = row.locator('[data-testid^="agent-player-link-"]');
            await expect(link).toBeVisible();

            await link.click();
            await expect(page.locator('[data-testid="agent-player-detail-title"]')).toContainText('Recent Referral');
        });
    });
});
