import AxeBuilder from '@axe-core/playwright';
import { expect, test, type Page } from '@playwright/test';

const email = process.env.E2E_EMAIL;
const password = process.env.E2E_PASSWORD;

if (process.env.CI && (!email || !password)) {
    throw new Error('E2E_EMAIL and E2E_PASSWORD are required for the Phase 8 Dashboard route in CI.');
}

const login = async (page: Page): Promise<void> => {
    await page.goto('/login');
    await page.getByRole('textbox', { name: 'Username', exact: true }).fill(email!);
    await page.getByLabel('Password').fill(password!);
    await page.getByRole('button', { name: 'Login' }).click();
    await expect(page).toHaveURL(/\/$/);
};

// Dashboard sections are exposed as a persistent horizontal submenu.
const selectDashboardView = async (page: Page, switcherLabel: string): Promise<void> => {
    await page.locator('#dashboard_view').getByRole('button', { name: switcherLabel, exact: true }).click();
};

test('Phase 8 Dashboard renders all six tabs inside the persistent Vue shell with no external-library overview chart', async ({ page }, testInfo) => {
    test.skip(!email || !password, 'Set E2E_EMAIL and E2E_PASSWORD to validate the Phase 8 Dashboard route.');

    const consoleProblems: string[] = [];

    page.on('console', (message) => {
        if (message.type() === 'error' || message.type() === 'warning') {
            consoleProblems.push(`${message.type()}: ${message.text()}`);
        }
    });
    page.on('pageerror', (error) => consoleProblems.push(`pageerror: ${error.message}`));

    await login(page);
    await page.goto('/dashboard');

    await expect(page.locator('html')).toHaveAttribute('data-frontend-root', 'inertia');
    await expect(page.locator('.application-shell')).toHaveCount(1);
    await expect(page.getByRole('heading', { level: 1 })).toBeVisible();

    await expect(page.locator('#gp_id')).toBeVisible();
    await expect(page.locator('#fund_id')).toBeVisible();
    await expect(page.locator('#investor_id')).toBeVisible();
    await expect(page.locator('#as_of_date')).toBeVisible();
    await expect(page.locator('#amount_scaling')).toBeVisible();

    const kpiCards = page.locator('.dashboard-overview-kpis .info-card');

    await expect(kpiCards).toHaveCount(4);

    // Overview chart must be the dependency-free SVG primitive — no canvas.
    await expect(page.locator('.dashboard-overview-chart svg.fund-performance-chart__svg')).toBeVisible();
    await expect(page.locator('.dashboard-overview-chart canvas')).toHaveCount(0);

    await expect(page.locator('.ui-top-performers')).toBeVisible();

    const views: Array<[string, string, string]> = [
        ['Commitments', 'Commitment', '.erp-pivot-table__table'],
        ['Performances', 'Call Distri & NAV', '.erp-pivot-table__table'],
        ['IRR', 'IRR calculation', '.erp-pivot-table__table'],
        ['Annual performance', 'Yearly performance', '.dashboard-table'],
    ];

    const activePanel = page.locator('[role="region"]:visible');

    for (const [switcherLabel, heading, tableSelector] of views) {
        await selectDashboardView(page, switcherLabel);
        await expect(page.getByRole('heading', { level: 4, name: heading })).toBeVisible();
        await expect(activePanel.locator(tableSelector).first()).toBeVisible();
    }

    // Quarterly history: Chart.js is lazy-loaded only once this tab is opened.
    await selectDashboardView(page, 'Quarterly history');
    await expect(page.getByRole('heading', { level: 4, name: 'Quarterly history' })).toBeVisible();
    await expect(activePanel.locator('.ui-loading-state, .dashboard-quarterly-charts canvas').first()).toBeVisible();
    await expect(activePanel.locator('.dashboard-quarterly-charts canvas').first()).toBeVisible({ timeout: 10_000 });

    const chartCount = await activePanel.locator('.dashboard-quarterly-charts canvas').count();

    expect(chartCount).toBeGreaterThan(0);

    expect(await page.evaluate(() => document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1)).toBe(true);

    const axe = await new AxeBuilder({ page })
        .withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
        .analyze();
    const blockingViolations = axe.violations.filter((violation) => (
        violation.impact === 'critical' || violation.impact === 'serious'
    ));

    expect(blockingViolations).toEqual([]);

    await page.screenshot({
        path: testInfo.outputPath(`dashboard-phase8-${testInfo.project.name}.png`),
        fullPage: true,
    });
    expect(consoleProblems).toEqual([]);
});

test('Dashboard shortens its date and keeps grouped pivot controls usable at constrained desktop width', async ({ page }, testInfo) => {
    test.skip(testInfo.project.name !== 'desktop-chromium', 'The reported regression is a constrained desktop layout.');
    test.skip(!email || !password, 'Set E2E_EMAIL and E2E_PASSWORD to validate the Phase 8 Dashboard route.');

    await page.setViewportSize({ width: 933, height: 964 });
    await login(page);
    await page.goto('/dashboard');

    const picker = page.locator('.dashboard-filter-panel .ui-date-picker');
    const fullDate = picker.locator('.ui-date-picker-trigger-label-long');
    const shortDate = picker.locator('.ui-date-picker-trigger-label-short');

    await expect(fullDate).toBeHidden();
    await expect(shortDate).toBeVisible();
    await expect(shortDate).toHaveText(/\d{1,2}\D\d{1,2}\D\d{2}/);
    await expect(picker.locator('.ui-date-picker-trigger-label')).toHaveAttribute('title', /\d{4}/);

    await selectDashboardView(page, 'Commitments');

    const pivot = page.locator('#dashboard_commitment_pivot');
    const groupControls = pivot.locator('.erp-pivot-table__group-control');
    const groupCount = await groupControls.count();

    await pivot.getByRole('button', { name: 'Collapse all' }).click();
    await expect(pivot.locator('.erp-pivot-table__group-control[aria-expanded="false"]')).toHaveCount(groupCount);
    await expect(pivot.locator('.erp-pivot-table__group-row--adaptive-summary')).toHaveCount(groupCount);
    await expect(pivot.locator('.erp-pivot-table__summary-row')).toHaveCount(0);
    await pivot.getByRole('button', { name: 'Expand all' }).click();
    await expect(pivot.locator('.erp-pivot-table__group-control[aria-expanded="true"]')).toHaveCount(groupCount);
    await expect(pivot.locator('.erp-pivot-table__group-row--adaptive-summary')).toHaveCount(0);
    await expect(pivot.locator('.erp-pivot-table__summary-row')).toHaveCount(groupCount);

    const fundSort = pivot.getByRole('button', { name: 'Sort Fund ascending' });
    const fundHeading = pivot.locator('th').filter({ hasText: 'Fund' });

    await fundSort.click();
    await expect(fundHeading).toHaveAttribute('aria-sort', 'ascending');

    const firstGroupToggle = pivot.locator('.erp-pivot-table__group-control').first();
    const controlledRowsId = await firstGroupToggle.getAttribute('aria-controls');

    expect(controlledRowsId).not.toBeNull();
    await expect(firstGroupToggle).toHaveAttribute('aria-expanded', 'true');
    await firstGroupToggle.click();
    await expect(firstGroupToggle).toHaveAttribute('aria-expanded', 'false');
    await expect(pivot.locator(`#${controlledRowsId}`)).toHaveAttribute('hidden', '');
    await expect(pivot.locator('.erp-pivot-table__group-row').first()).toHaveClass(/erp-pivot-table__group-row--adaptive-summary/);
    await expect(pivot.locator('.erp-pivot-table__group-row').first().locator('.erp-pivot-table__summary-cell').first()).toBeVisible();
    await expect(pivot.locator('.erp-pivot-table__summary-row')).toHaveCount(groupCount - 1);
    await expect(pivot.locator('.erp-pivot-table__persistent-scroll')).toBeVisible();

    expect(await page.evaluate(() => document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1)).toBe(true);

    await page.screenshot({
        path: testInfo.outputPath('dashboard-pivot-constrained-desktop.png'),
        fullPage: true,
    });
});

test('Phase 8 Dashboard filter form performs a same-shell Inertia visit that preserves the active tab', async ({ page }, testInfo) => {
    test.skip(testInfo.project.name !== 'desktop-chromium', 'One browser project is enough for the filter round-trip.');
    test.skip(!email || !password, 'Set E2E_EMAIL and E2E_PASSWORD to validate the Phase 8 Dashboard route.');

    await login(page);
    await page.goto('/dashboard');

    await selectDashboardView(page, 'Commitments');
    await expect(page.getByRole('heading', { level: 4, name: 'Commitment' })).toBeVisible();

    const shellMarker = await page.locator('.application-shell').evaluate((shell) => {
        const marker = crypto.randomUUID();

        (shell as HTMLElement & { __phaseEightDashboardMarker?: string }).__phaseEightDashboardMarker = marker;

        return marker;
    });

    await page.getByRole('button', { name: 'Apply filters' }).click();
    await page.waitForURL(/dashboard_view=commitment/);

    await expect.poll(() => page.locator('.application-shell').evaluate((shell) => (
        shell as HTMLElement & { __phaseEightDashboardMarker?: string }
    ).__phaseEightDashboardMarker)).toBe(shellMarker);
    await expect(page.getByRole('heading', { level: 4, name: 'Commitment' })).toBeVisible();
});

test('Dashboard multiselect filters keep their checkbox menu open and submit repeated values', async ({ page }, testInfo) => {
    test.skip(testInfo.project.name !== 'desktop-chromium', 'One browser project is enough for the multiselect round-trip.');
    test.skip(!email || !password, 'Set E2E_EMAIL and E2E_PASSWORD to validate the Phase 8 Dashboard route.');

    await login(page);
    await page.goto('/dashboard');

    const trigger = page.locator('#fund_id');

    await trigger.click();

    const dialog = page.locator('#fund_id_popover');
    const checkboxes = dialog.getByRole('checkbox');

    await expect(dialog).toBeVisible();
    expect(await checkboxes.count()).toBeGreaterThan(1);
    await checkboxes.nth(0).click();
    await expect(dialog).toBeVisible();
    await checkboxes.nth(1).click();
    await expect(dialog).toBeVisible();
    await expect(trigger).toContainText('2 funds');

    await dialog.getByRole('button', { name: 'Done' }).click();
    await page.getByRole('button', { name: 'Apply filters' }).click();
    await page.waitForURL(/fund_id/);

    const selectedFundParameters = await page.evaluate(() => Array.from(new URL(window.location.href).searchParams.entries())
        .filter(([key]) => key.startsWith('fund_id')));

    expect(selectedFundParameters).toHaveLength(2);
});
