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

// AGENT (+10000000002) is a master agent whose fixture referral code is
// ABCDEF01. AppFixtures wires no downline, so the roster test creates its own.

test.describe('Agent Portal — downline pages role guard', () => {
    for (const [path, testid] of [
        ['/agent/live-players', 'agent-live-players-title'],
        ['/agent/downline',     'agent-downline-title'],
        ['/agent/requests',     'agent-requests-title'],
    ] as const) {
        test(`non-agent USER cannot access ${path}`, async ({ page }) => {
            await loginAs(page, USER.mobile, USER.password);
            await page.goto(`${BASE_URL}${path}`);
            await expect(page.locator(`[data-testid="${testid}"]`)).not.toBeVisible();
        });
    }
});

test.describe('Agent Portal — downline pages', () => {

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

    test('Live Players page loads (table or empty state)', async ({ page }) => {
        await page.goto(`${BASE_URL}/agent/live-players`);
        await expect(page.locator('[data-testid="agent-live-players-title"]')).toBeVisible();
        const table = page.locator('[data-testid="agent-live-players-table"]');
        const empty = page.locator('[data-testid="agent-live-players-empty"]');
        await expect(table.or(empty)).toBeVisible();
    });

    test('Live Players pins newly-registered bettors first and keeps a stable order', async ({ page }) => {
        // Fixtures: "Recent Referral" (registered today) and "Earlier Referral"
        // (registered 10 days ago) each have one equal-stake Win bet on today's event.
        await page.goto(`${BASE_URL}/agent/live-players`);
        const rows = page.locator('[data-testid="agent-live-players-table"] tbody tr.table-row');
        if (await rows.count() < 2) {
            test.skip(); // no published event / no downline bets today
            return;
        }

        const orderOf = async () => (await rows.locator('td:first-child').allInnerTexts()).map(t => t.trim().replace(/\s+New$/, ''));

        // Newest registration is pinned above the equal-stake older player…
        const first = await orderOf();
        const iRecent  = first.findIndex(n => n.includes('Recent Referral'));
        const iEarlier = first.findIndex(n => n.includes('Earlier Referral'));
        expect(iRecent).toBeGreaterThanOrEqual(0);
        expect(iRecent).toBeLessThan(iEarlier);

        // …and carries the "New" badge; the older one does not.
        const recentRow = rows.filter({ hasText: 'Recent Referral' });
        await expect(recentRow.locator('[data-testid^="badge-new-player-"]')).toBeVisible();
        await expect(rows.filter({ hasText: 'Earlier Referral' }).locator('[data-testid^="badge-new-player-"]')).toHaveCount(0);

        // Order is deterministic across an identical reload (no reshuffle).
        await page.reload();
        expect(await orderOf()).toEqual(first);
    });

    test('Downline page loads with search form and table', async ({ page }) => {
        await page.goto(`${BASE_URL}/agent/downline`);
        await expect(page.locator('[data-testid="agent-downline-title"]')).toBeVisible();
        await expect(page.locator('[data-testid="agent-downline-search-form"]')).toBeVisible();
        await expect(page.locator('[data-testid="agent-downline-table"]')).toBeVisible();
    });

    test('Deposits & Withdrawals page loads with status filters and type tabs', async ({ page }) => {
        await page.goto(`${BASE_URL}/agent/requests`);
        await expect(page.locator('[data-testid="agent-requests-title"]')).toBeVisible();
        await expect(page.locator('[data-testid="agent-requests-table"]')).toBeVisible();
        await expect(page.locator('[data-testid="filter-pending"]')).toBeVisible();
        await expect(page.locator('[data-testid="filter-approved"]')).toBeVisible();
        await expect(page.locator('[data-testid="filter-rejected"]')).toBeVisible();
        await expect(page.locator('[data-testid="agent-requests-tab-deposits"]')).toBeVisible();
        await expect(page.locator('[data-testid="agent-requests-tab-withdrawals"]')).toBeVisible();
    });

    test('status filter and type toggle update the URL', async ({ page }) => {
        await page.goto(`${BASE_URL}/agent/requests`);

        await page.click('[data-testid="filter-approved"]');
        await expect(page).toHaveURL(/status=approved/);

        await page.click('[data-testid="agent-requests-tab-withdrawals"]');
        await expect(page).toHaveURL(/type=withdrawals/);
    });

    test('the grouped nav dropdowns open and navigate', async ({ page }) => {
        await page.goto(`${BASE_URL}/agent/dashboard`);

        // Downline ▾ → Live Players
        await page.click('[data-testid="agent-nav-downline-menu"]');
        await page.click('[data-testid="agent-nav-live-players"]');
        await expect(page).toHaveURL(/\/agent\/live-players$/);

        // Payments ▾ → Deposits & Withdrawals
        await page.click('[data-testid="agent-nav-payments-menu"]');
        await page.click('[data-testid="agent-nav-requests"]');
        await expect(page).toHaveURL(/\/agent\/requests$/);
    });
});

test.describe('Agent Portal — downline roster', () => {
    test('a newly referred player appears in the agent downline table', async ({ page }) => {
        const { mobile } = await registerUserWithReferralCode(page, 'ABCDEF01');

        await loginAs(page, AGENT.mobile, AGENT.password);
        await page.goto(`${BASE_URL}/agent/downline`);

        await expect(page.locator('[data-testid="agent-downline-table"]')).toContainText(mobile);
    });
});

// AppFixtures puts sub-agent "Sub Ken" (+10000000011) under AGENT, with its
// own player Devon Ken (+10000000105). The agent filter lists only the
// selected agent's direct players (their "Referred By").
test.describe('Agent Portal — downline agent filter', () => {
    const SUB_KEN_PLAYER = '+10000000105';

    test('filtering by agent lists only that agent\'s direct players', async ({ page }) => {
        const { mobile: directPlayer } = await registerUserWithReferralCode(page, 'ABCDEF01');

        await loginAs(page, AGENT.mobile, AGENT.password);
        await page.goto(`${BASE_URL}/agent/downline`);

        const filter = page.locator('[data-testid="agent-downline-agent-filter"]');
        const table  = page.locator('[data-testid="agent-downline-table"]');

        // All agents: the whole downline.
        await expect(table).toContainText(SUB_KEN_PLAYER);
        await expect(table).toContainText(directPlayer);

        // A sub-agent: only the players it referred.
        await filter.selectOption({ label: 'Sub Ken (Sub-agent)' });
        await expect(page).toHaveURL(/[?&]agent=\d+/);
        await expect(table).toContainText(SUB_KEN_PLAYER);
        await expect(table).not.toContainText(directPlayer);
        await expect(page.locator('p', { hasText: 'referred by Sub Ken' })).toBeVisible();

        // Search keeps the agent filter.
        await page.fill('[data-testid="agent-downline-search-input"]', 'Devon');
        await page.click('[data-testid="agent-downline-search-btn"]');
        await expect(filter).toHaveValue(/\d+/);
        await expect(table).toContainText(SUB_KEN_PLAYER);
        await page.click('[data-testid="agent-downline-search-clear"]');
        await expect(page).toHaveURL(/\/agent\/downline$/);
        await expect(page.locator('[data-testid="agent-downline-search-input"]')).toHaveValue('');

        // Me: the agent's own direct players only.
        await filter.selectOption({ label: 'Me — my direct players' });
        await expect(table).toContainText(directPlayer);
        await expect(table).not.toContainText(SUB_KEN_PLAYER);

        // Back to all agents.
        await filter.selectOption({ label: 'All agents' });
        await expect(page).toHaveURL(/[?&]agent=(&|$)/);
        await expect(table).toContainText(SUB_KEN_PLAYER);
        await expect(table).toContainText(directPlayer);
    });

    test('an agent outside the downline is ignored', async ({ page }) => {
        await loginAs(page, AGENT.mobile, AGENT.password);
        await page.goto(`${BASE_URL}/agent/downline?agent=999999`);
        await expect(page.locator('[data-testid="agent-downline-agent-filter"]')).toHaveValue('');
        await expect(page.locator('[data-testid="agent-downline-table"]')).toContainText(SUB_KEN_PLAYER);
    });
});
