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

test.describe('WFBO Withdrawal Management', () => {

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

    test('withdrawals page loads with table', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
    });

    test('withdrawal rows show the requester agent-tier badge', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);

        // Seeded pending withdrawals (AppFixtures): +10000000002 is a Master
        // Agent, +10000000006 is an Agent.
        const masterRow = page.locator('[data-testid^="withdrawal-row-"]').filter({ hasText: '+10000000002' });
        await expect(masterRow.locator('.badge-agent-inline')).toHaveText('Master Agent');

        const agentRow = page.locator('[data-testid^="withdrawal-row-"]').filter({ hasText: '+10000000006' });
        await expect(agentRow.locator('.badge-agent-inline')).toHaveText('Agent');

        // A plain player's withdrawal row, if any, carries no tier badge.
        const playerRow = page.locator('[data-testid^="withdrawal-row-"]').filter({ hasText: '+10000000001' });
        if (await playerRow.count() > 0) {
            await expect(playerRow.first().locator('.badge-agent-inline')).toHaveCount(0);
        }
    });

    test('shows Total Deposits and Total Withdrawals Today cards', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);

        const depositsCard = page.locator('[data-testid="stat-deposits-today"]');
        await expect(depositsCard).toBeVisible();
        await expect(depositsCard).toContainText('Total Deposits');
        await expect(depositsCard).toContainText('Today');
        await expect(depositsCard).toContainText('₱');
        const depositsPending = page.locator('[data-testid="stat-deposits-pending"]');
        await expect(depositsPending).toContainText('Pending');
        await expect(depositsPending).toContainText('₱');

        const withdrawalsCard = page.locator('[data-testid="stat-withdrawals-today"]');
        await expect(withdrawalsCard).toBeVisible();
        await expect(withdrawalsCard).toContainText('Total Withdrawals');
        await expect(withdrawalsCard).toContainText('Today');
        await expect(withdrawalsCard).toContainText('₱');
        const withdrawalsPending = page.locator('[data-testid="stat-withdrawals-pending"]');
        await expect(withdrawalsPending).toContainText('Pending');
        await expect(withdrawalsPending).toContainText('₱');
    });

    test('pending withdrawal tier totals are all-time and reconcile with the headline', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);

        // AppFixtures seeds pending withdrawals: ₱500 Master Agent (+10000000002)
        // and ₱300 Agent (+10000000006) today, plus ₱175 for a player submitted
        // 10 days ago — the all-time pending figures must include that one.
        await expect(page.locator('[data-testid="stat-withdrawals-tier-master-agent-pending"]'))
            .toContainText('Pending: ₱500.00 (1)');
        await expect(page.locator('[data-testid="stat-withdrawals-tier-agent-pending"]'))
            .toContainText('Pending: ₱300.00 (1)');
        await expect(page.locator('[data-testid="stat-withdrawals-tier-sub-agent-pending"]'))
            .toContainText('Pending: ₱0.00 (0)');
        await expect(page.locator('[data-testid="stat-withdrawals-tier-player-pending"]'))
            .toContainText('Pending: ₱175.00 (1)');

        // The four tier pending totals reconcile with the headline (all-time) card.
        await expect(page.locator('[data-testid="stat-withdrawals-pending"]'))
            .toContainText('Pending: ₱975.00 (3)');
    });

    test('approved tier & headline totals are by approval date, and reconcile', async ({ page }) => {
        // AppFixtures seeds two APPROVED player withdrawals: ₱400 approved today
        // (requested 3 days ago) — counts; ₱250 requested today but approved
        // 3 days ago — does NOT count in today's figures.
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);

        const player = page.locator('[data-testid="stat-withdrawals-tier-player"]');
        await expect(player.locator('.stat-value--lg')).toHaveText('₱400.00');
        await expect(player).toContainText('1 approved');

        // Headline "Total Withdrawals Today" also uses approval date.
        await expect(page.locator('[data-testid="stat-withdrawals-today"] .stat-value--lg'))
            .toHaveText('₱400.00');

        // The four tier approved amounts sum to the headline.
        const parseAmt = async (loc: string) =>
            parseFloat((await page.locator(loc).innerText()).replace(/[₱,\s]/g, ''));
        let tierSum = 0;
        for (const slug of ['master-agent', 'agent', 'sub-agent', 'player']) {
            tierSum += await parseAmt(`[data-testid="stat-withdrawals-tier-${slug}"] .stat-value--lg`);
        }
        expect(tierSum).toBeCloseTo(await parseAmt('[data-testid="stat-withdrawals-today"] .stat-value--lg'), 2);
    });

    test('status filter tabs are visible', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await expect(page.locator('[data-testid="withdrawal-status-filters"]')).toBeVisible();
    });

    test('clicking Approved filter reloads with filtered view', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        const approvedFilter = page.locator('[data-testid="withdrawal-status-filters"]').locator('text=Approved');
        await approvedFilter.click();
        await page.waitForURL(/status=approved/, { timeout: 10000 });
        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
    });

    test('clicking Rejected filter reloads with filtered view', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        const rejectedFilter = page.locator('[data-testid="withdrawal-status-filters"]').locator('text=Rejected');
        await rejectedFilter.click();
        await page.waitForURL(/status=rejected/, { timeout: 10000 });
        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
    });

    test('can approve a pending withdrawal if one exists', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        const approveBtn = page.locator('[data-testid^="btn-approve-"]').first();
        if (await approveBtn.count() === 0) {
            test.skip();
            return;
        }
        const id = (await approveBtn.getAttribute('data-testid'))?.replace('btn-approve-', '');
        await approveBtn.click();
        await page.waitForLoadState('networkidle');
        // If AJAX failed (e.g. parallel test processed it first), reload to see actual state
        if (await page.locator(`[data-testid="withdrawal-row-${id}"]`).count() > 0) {
            await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        }
        await expect(page.locator(`[data-testid="btn-approve-${id}"]`)).not.toBeAttached({ timeout: 10000 });
    });

    test('can reject a pending withdrawal with a review note', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        const rejectBtn = page.locator('[data-testid^="btn-reject-"]').first();
        if (await rejectBtn.count() === 0) {
            test.skip();
            return;
        }
        const id = (await rejectBtn.getAttribute('data-testid'))?.replace('btn-reject-', '');
        const noteInput = page.locator(`[data-testid="input-review-note-${id}"]`);
        if (await noteInput.count() > 0) {
            await noteInput.fill('Insufficient bank details');
        }
        await rejectBtn.click();
        await page.waitForLoadState('networkidle');
        if (await page.locator(`[data-testid="withdrawal-row-${id}"]`).count() > 0) {
            await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        }
        await expect(page.locator(`[data-testid="btn-reject-${id}"]`)).not.toBeAttached({ timeout: 10000 });
    });

    test('FINANCE user can access withdrawals page', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
    });

    test('ADMIN user can access withdrawals page', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
    });

    test('OPERATIONS user is blocked from withdrawals page', async ({ page }) => {
        await loginAs(page, OPERATIONS.mobile, OPERATIONS.password);
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await expect(page.locator('[data-testid="withdrawals-table"]')).not.toBeVisible();
    });

    test('WFBO sidebar shows withdrawals nav link', async ({ page }) => {
        await loginAs(page, ADMIN.mobile, ADMIN.password);
        await page.goto(`${BASE_URL}/wfbo`, { waitUntil: 'networkidle' });
        await expect(page.locator('[data-testid="wfbo-sidebar"]')).toBeVisible();
        await expect(page.locator('[data-testid="wfbo-nav-withdrawals"]')).toBeVisible();
    });

    test('search form is visible on withdrawals page', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await expect(page.locator('[data-testid="withdrawal-search-form"]')).toBeVisible();
        await expect(page.locator('[data-testid="input-withdrawal-search"]')).toBeVisible();
        await expect(page.locator('[data-testid="btn-withdrawal-search"]')).toBeVisible();
    });

    test('search input auto-submits via debounce without clicking Search', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await page.waitForLoadState('networkidle');
        // Focus and type to ensure reliable input events
        await page.locator('[data-testid="input-withdrawal-search"]').focus();
        await page.keyboard.type('DebounceAutoTest', { delay: 50 });
        // Debounce fires at 400ms; wait for navigation/URL change
        await page.waitForURL(/search=DebounceAutoTest/, { timeout: 10000 });
        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
    });

    test('sidebar withdrawal badge element exists in DOM for FINANCE user', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        // Badge span is rendered server-side and managed by wfbo-pending controller
        await expect(page.locator('[data-wfbo-pending-target="withdrawalBadge"]')).toBeAttached();
    });

    test('searching by name filters the withdrawals table', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await page.fill('[data-testid="input-withdrawal-search"]', 'Test');
        await page.click('[data-testid="btn-withdrawal-search"]');
        await page.waitForLoadState('networkidle');

        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
        expect(page.url()).toContain('search=Test');
    });

    test('searching by mobile number filters the withdrawals table', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        await page.fill('[data-testid="input-withdrawal-search"]', '+1000');
        await page.click('[data-testid="btn-withdrawal-search"]');
        await page.waitForLoadState('networkidle');

        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
        expect(page.url()).toContain('search=');
    });

    test('clear button removes search and reloads', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals?search=Test`);
        await expect(page.locator('[data-testid="btn-withdrawal-search-clear"]')).toBeVisible();
        await page.click('[data-testid="btn-withdrawal-search-clear"]');
        await page.waitForLoadState('networkidle');

        expect(page.url()).not.toContain('search=');
        await expect(page.locator('[data-testid="withdrawals-table"]')).toBeVisible();
    });

    test('search preserves status filter', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals?status=pending`);
        await page.fill('[data-testid="input-withdrawal-search"]', 'User');
        await page.click('[data-testid="btn-withdrawal-search"]');
        await page.waitForLoadState('networkidle');

        expect(page.url()).toContain('status=pending');
        expect(page.url()).toContain('search=User');
    });

    test('receipt view modal opens when View button is clicked', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        const viewBtn = page.locator('[data-testid^="btn-view-receipt-"]').first();
        if (await viewBtn.count() === 0) {
            test.skip();
            return;
        }
        await viewBtn.click();
        await expect(page.locator('#receipt-modal')).toBeVisible();
    });

    test('every withdrawal row carries a bank-tint class', async ({ page }) => {
        await page.goto(`${BASE_URL}/wfbo/withdrawals`);
        const rows = page.locator('[data-testid^="withdrawal-row-"]');
        const count = await rows.count();
        if (count === 0) {
            test.skip();
            return;
        }
        for (let i = 0; i < count; i++) {
            await expect(rows.nth(i)).toHaveClass(/table-row--(gcash|maya|gotyme|other)/);
        }
    });

    test('rows are tinted by bank/e-wallet, matching the deposit list', async ({ page }) => {
        const acctGcash = `55${Date.now().toString().slice(-8)}`;
        const acctBdo   = `66${Date.now().toString().slice(-8)}`;

        await adjustWalletAsAuditor(page, USER.mobile, '500.00', 'withdrawal row-color test');

        await loginAs(page, USER.mobile, USER.password);
        await page.goto(`${BASE_URL}/withdrawal`);
        const form = page.locator('[data-testid="withdrawal-form"]');
        if (await form.count() === 0) {
            test.skip(); // withdrawal window closed by another test's schedule
            return;
        }

        const submitWithdrawal = async (bankName: string, accountNumber: string): Promise<void> => {
            await page.goto(`${BASE_URL}/withdrawal`);
            await page.fill('[data-testid="input-withdrawal-amount"]', '50');
            await page.selectOption('[data-testid="input-withdrawal-bank-name"]', bankName);
            await page.fill('[data-testid="input-withdrawal-bank-account-name"]', 'Row Color Test');
            await page.fill('[data-testid="input-withdrawal-bank-account-number"]', accountNumber);
            await page.click('[data-testid="btn-withdrawal-submit"]');
            await expect(page.locator('[data-testid="flash-success"]')).toBeVisible();
        };

        await submitWithdrawal('GCASH', acctGcash);
        await submitWithdrawal('BDO', acctBdo);

        await loginAs(page, FINANCE.mobile, FINANCE.password);

        await page.goto(`${BASE_URL}/wfbo/withdrawals?search=${acctGcash}`);
        await expect(page.locator('[data-testid^="withdrawal-row-"]').first()).toHaveClass(/table-row--gcash/);

        await page.goto(`${BASE_URL}/wfbo/withdrawals?search=${acctBdo}`);
        await expect(page.locator('[data-testid^="withdrawal-row-"]').first()).toHaveClass(/table-row--other/);
    });

});
