import AxeBuilder from '@axe-core/playwright';
import { expect, test, type Page, type TestInfo } from '@playwright/test';
import { writeFile } from 'node:fs/promises';

type SearchPerformanceState = {
    longTasks: number[];
    layoutShifts: number[];
    interactions: Record<string, number>;
    lcpMs: number | null;
    eventTimingSupported: boolean;
};

type BrowserProblem = {
    type: 'error' | 'warning' | 'pageerror';
    text: string;
    url: string;
};

const email = process.env.E2E_EMAIL;
const password = process.env.E2E_PASSWORD;
const localColdTransferBudgetBytes = 700_000;

if (process.env.CI && (!email || !password)) {
    throw new Error('E2E_EMAIL and E2E_PASSWORD are required for the authenticated search pilot in CI.');
}

const attachJson = async (testInfo: TestInfo, name: string, value: unknown): Promise<void> => {
    const path = testInfo.outputPath(`${name}.json`);

    await writeFile(path, JSON.stringify(value, null, 2));
    await testInfo.attach(name, { path, contentType: 'application/json' });
};

const attachScreenshot = async (page: Page, testInfo: TestInfo, name: string): Promise<void> => {
    const path = testInfo.outputPath(`${name}.png`);

    await page.screenshot({ path, fullPage: true });
    await testInfo.attach(name, { path, contentType: 'image/png' });
};

const installPerformanceObservers = async (page: Page): Promise<void> => {
    await page.addInitScript(() => {
        const state: SearchPerformanceState = {
            longTasks: [],
            layoutShifts: [],
            interactions: {},
            lcpMs: null,
            eventTimingSupported: false,
        };

        Object.defineProperty(window, '__searchPilotPerformance', {
            configurable: true,
            value: state,
        });

        try {
            new PerformanceObserver((list) => {
                for (const entry of list.getEntries()) {
                    state.longTasks.push(entry.duration);
                }
            }).observe({ type: 'longtask', buffered: true });
        } catch {
            // Browser support varies; null/empty values remain explicit in the artifact.
        }

        try {
            new PerformanceObserver((list) => {
                for (const entry of list.getEntries()) {
                    const shift = entry as PerformanceEntry & { hadRecentInput?: boolean; value?: number };

                    if (!shift.hadRecentInput && typeof shift.value === 'number') {
                        state.layoutShifts.push(shift.value);
                    }
                }
            }).observe({ type: 'layout-shift', buffered: true });
        } catch {
            // Layout Instability is not exposed by every browser engine.
        }

        try {
            new PerformanceObserver((list) => {
                const latest = list.getEntries().at(-1);

                if (latest) {
                    state.lcpMs = latest.startTime;
                }
            }).observe({ type: 'largest-contentful-paint', buffered: true });
        } catch {
            // LCP is not exposed by every browser engine.
        }

        try {
            const observer = new PerformanceObserver((list) => {
                for (const entry of list.getEntries() as PerformanceEventTiming[]) {
                    if (entry.interactionId > 0) {
                        const key = String(entry.interactionId);
                        state.interactions[key] = Math.max(state.interactions[key] ?? 0, entry.duration);
                    }
                }
            });

            observer.observe({
                type: 'event',
                buffered: true,
                durationThreshold: 16,
            } as PerformanceObserverInit & { durationThreshold: number });
            state.eventTimingSupported = true;
        } catch {
            // Event Timing is optional in the local browser.
        }
    });
};

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(/\/$/);
};

const clearBrowserCache = async (page: Page): Promise<void> => {
    const session = await page.context().newCDPSession(page);

    await session.send('Network.enable');
    await session.send('Network.clearBrowserCache');
    await session.detach();
};

const collectColdMetrics = async (page: Page) => page.evaluate(() => {
    const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
    const resources = performance.getEntriesByType('resource') as PerformanceResourceTiming[];
    const state = (window as typeof window & {
        __searchPilotPerformance?: SearchPerformanceState;
    }).__searchPilotPerformance;

    return {
        responseMs: Math.round(navigation.responseEnd),
        domContentLoadedMs: Math.round(navigation.domContentLoadedEventEnd),
        loadMs: Math.round(navigation.loadEventEnd),
        transferredBytes: Math.round(resources.reduce((total, entry) => total + entry.transferSize, 0)),
        decodedBytes: Math.round(resources.reduce((total, entry) => total + entry.decodedBodySize, 0)),
        lcpMs: state?.lcpMs === null || state?.lcpMs === undefined ? null : Math.round(state.lcpMs),
        cumulativeLayoutShift: Number((state?.layoutShifts.reduce((total, value) => total + value, 0) ?? 0).toFixed(4)),
        longTasksOver50Ms: (state?.longTasks ?? []).filter((duration) => duration >= 50),
    };
});

type ColdMetrics = Awaited<ReturnType<typeof collectColdMetrics>>;

const median = (values: number[]): number => {
    const sorted = [...values].sort((first, second) => first - second);

    return sorted[Math.floor(sorted.length / 2)] ?? 0;
};

const summarizeColdMetrics = (samples: ColdMetrics[]): ColdMetrics => {
    const lcpSamples = samples
        .map((sample) => sample.lcpMs)
        .filter((value): value is number => value !== null);

    return {
        responseMs: median(samples.map((sample) => sample.responseMs)),
        domContentLoadedMs: median(samples.map((sample) => sample.domContentLoadedMs)),
        loadMs: median(samples.map((sample) => sample.loadMs)),
        transferredBytes: median(samples.map((sample) => sample.transferredBytes)),
        decodedBytes: median(samples.map((sample) => sample.decodedBytes)),
        lcpMs: lcpSamples.length === samples.length ? median(lcpSamples) : null,
        cumulativeLayoutShift: median(samples.map((sample) => sample.cumulativeLayoutShift)),
        longTasksOver50Ms: samples.flatMap((sample) => sample.longTasksOver50Ms),
    };
};

const resetWarmMetrics = async (page: Page): Promise<number> => page.evaluate(() => {
    performance.clearResourceTimings();

    const state = (window as typeof window & {
        __searchPilotPerformance?: SearchPerformanceState;
    }).__searchPilotPerformance;

    if (state) {
        state.longTasks = [];
        state.layoutShifts = [];
        state.interactions = {};
    }

    return performance.now();
});

const collectWarmMetrics = async (page: Page, startedAt: number) => page.evaluate((start) => {
    const resources = performance.getEntriesByType('resource') as PerformanceResourceTiming[];
    const state = (window as typeof window & {
        __searchPilotPerformance?: SearchPerformanceState;
    }).__searchPilotPerformance;
    const interactionDurations = Object.values(state?.interactions ?? {}).sort((a, b) => b - a);
    const inpIndex = Math.min(Math.floor(interactionDurations.length / 50), interactionDurations.length - 1);
    const inpStatus = !state?.eventTimingSupported
        ? 'unsupported'
        : inpIndex < 0
            ? 'below-16ms-threshold'
            : 'measured';

    return {
        durationMs: Math.round(performance.now() - start),
        requestCount: resources.length,
        transferredBytes: Math.round(resources.reduce((total, entry) => total + entry.transferSize, 0)),
        decodedBytes: Math.round(resources.reduce((total, entry) => total + entry.decodedBodySize, 0)),
        inpMs: inpIndex < 0 ? null : Math.round(interactionDurations[inpIndex]),
        inpStatus,
        inpObserverThresholdMs: 16,
        cumulativeLayoutShift: Number((state?.layoutShifts.reduce((total, value) => total + value, 0) ?? 0).toFixed(4)),
        longTasksOver50Ms: (state?.longTasks ?? []).filter((duration) => duration >= 50),
    };
}, startedAt);

const assertNoOverflow = async (page: Page): Promise<void> => {
    const widths = await page.evaluate(() => ({
        client: document.documentElement.clientWidth,
        scroll: document.documentElement.scrollWidth,
    }));

    expect(widths.scroll, JSON.stringify(widths)).toBeLessThanOrEqual(widths.client + 1);
};

const assertTopbarDoesNotOverlap = async (page: Page): Promise<void> => {
    const geometry = await page.evaluate(() => {
        const searchElement = document.querySelector<HTMLElement>('.application-shell__search');
        const accountElement = document.querySelector<HTMLElement>('.application-shell__topbar-actions');

        if (!searchElement || !accountElement) {
            return null;
        }

        const searchStyle = window.getComputedStyle(searchElement);

        if (searchStyle.display === 'none' || searchStyle.visibility === 'hidden') {
            return { searchHidden: true, searchRight: 0, accountLeft: 0 };
        }

        const search = searchElement.getBoundingClientRect();
        const account = accountElement.getBoundingClientRect();

        return {
            searchHidden: false,
            searchRight: search.right,
            accountLeft: account.left,
        };
    });

    expect(geometry).not.toBeNull();

    if (!geometry?.searchHidden) {
        expect(geometry?.searchRight ?? Number.POSITIVE_INFINITY).toBeLessThanOrEqual(
            (geometry?.accountLeft ?? Number.NEGATIVE_INFINITY) + 0.5,
        );
    }
};

const assertPersistentShell = async (page: Page): Promise<void> => {
    await expect(page.locator('.application-shell')).toHaveCount(1);
    await expect(page.locator('#application-navigation')).toHaveCount(1);
    await expect(page.locator('#application-content')).toHaveCount(1);
    await expect(page.locator('.application-shell__topbar')).toHaveCount(1);
    await expect(page.locator('#top-menu, #left-menu')).toHaveCount(0);
};

const assertSearchCardFillsSection = async (page: Page): Promise<void> => {
    const geometry = await page.evaluate(() => {
        const section = document.querySelector('#application-content')?.getBoundingClientRect();
        const card = document.querySelector('.search-page')?.getBoundingClientRect();

        return section && card
            ? {
                leftInset: card.left - section.left,
                rightInset: section.right - card.right,
                cardHeight: card.height,
                sectionHeight: section.height,
            }
            : null;
    });

    expect(geometry).not.toBeNull();
    expect(geometry?.leftInset ?? 0).toBeGreaterThanOrEqual(15);
    expect(geometry?.leftInset ?? 0).toBeLessThanOrEqual(17);
    expect(geometry?.rightInset ?? 0).toBeGreaterThanOrEqual(15);
    expect(geometry?.rightInset ?? 0).toBeLessThanOrEqual(17);
    expect(geometry?.cardHeight ?? 0).toBeGreaterThanOrEqual((geometry?.sectionHeight ?? 0) - 33);
};

const assertSearchCardUsesApplicationDensity = async (page: Page): Promise<void> => {
    const density = await page.evaluate(() => {
        const header = document.querySelector<HTMLElement>('.search-page > .ui-page-header');
        const body = document.querySelector<HTMLElement>('.search-page__body');
        const form = document.querySelector<HTMLElement>('.search-page__form');

        if (!header || !body || !form) {
            return null;
        }

        const headerStyle = window.getComputedStyle(header);
        const bodyStyle = window.getComputedStyle(body);
        const headerBounds = header.getBoundingClientRect();
        const formBounds = form.getBoundingClientRect();

        return {
            headerPaddingLeft: Number.parseFloat(headerStyle.paddingLeft),
            headerPaddingRight: Number.parseFloat(headerStyle.paddingRight),
            bodyPaddingTop: Number.parseFloat(bodyStyle.paddingTop),
            bodyPaddingRight: Number.parseFloat(bodyStyle.paddingRight),
            bodyPaddingBottom: Number.parseFloat(bodyStyle.paddingBottom),
            bodyPaddingLeft: Number.parseFloat(bodyStyle.paddingLeft),
            bodyGap: Number.parseFloat(bodyStyle.rowGap),
            contentAlignmentDelta: Math.abs(
                headerBounds.left + Number.parseFloat(headerStyle.paddingLeft) - formBounds.left,
            ),
        };
    });

    expect(density).not.toBeNull();
    expect(density).toMatchObject({
        headerPaddingLeft: 16,
        headerPaddingRight: 16,
        bodyPaddingTop: 16,
        bodyPaddingRight: 16,
        bodyPaddingBottom: 16,
        bodyPaddingLeft: 16,
        bodyGap: 16,
    });
    expect(density?.contentAlignmentDelta ?? Number.POSITIVE_INFINITY).toBeLessThanOrEqual(0.5);
};

const assertGlobalSearchPanelMatchesTrigger = async (page: Page): Promise<void> => {
    const trigger = page.locator('.application-shell__search');
    const globalInput = page.locator('#application-search');
    const panel = page.locator('.application-global-search__panel[role="dialog"]');

    if (!(await trigger.isVisible())) {
        return;
    }

    const triggerBefore = await trigger.boundingBox();
    const topbarBefore = await page.locator('.application-shell__topbar').boundingBox();

    await trigger.click();
    await expect(panel).toBeVisible();
    await expect(trigger).toHaveAttribute('aria-expanded', 'true');
    await expect(globalInput).toBeFocused();
    await expect(globalInput).toHaveAttribute('aria-expanded', 'true');

    const geometry = await page.evaluate(() => {
        const form = document.querySelector('.application-shell__search')?.getBoundingClientRect();
        const floatingPanel = document.querySelector('.application-global-search__panel')?.getBoundingClientRect();

        return form && floatingPanel
            ? {
                formLeft: form.left,
                formWidth: form.width,
                panelLeft: floatingPanel.left,
                panelRight: floatingPanel.right,
                panelWidth: floatingPanel.width,
                viewportLeft: window.visualViewport?.offsetLeft ?? 0,
                viewportWidth: window.visualViewport?.width ?? document.documentElement.clientWidth,
            }
            : null;
    });

    expect(geometry).not.toBeNull();
    const viewportPadding = 10;
    const availableWidth = (geometry?.viewportWidth ?? 0) - (viewportPadding * 2);
    const expectedWidth = Math.min(520, availableWidth);
    const leftBoundary = (geometry?.viewportLeft ?? 0) + viewportPadding;
    const rightBoundary = (geometry?.viewportLeft ?? 0) + (geometry?.viewportWidth ?? 0) - viewportPadding;
    const expectedLeft = Math.min(
        Math.max(geometry?.formLeft ?? 0, leftBoundary),
        Math.max(leftBoundary, rightBoundary - expectedWidth),
    );

    expect(Math.abs((geometry?.panelWidth ?? 0) - expectedWidth)).toBeLessThanOrEqual(1);
    expect(Math.abs((geometry?.panelLeft ?? 0) - expectedLeft)).toBeLessThanOrEqual(1);
    expect(geometry?.panelRight ?? Number.POSITIVE_INFINITY).toBeLessThanOrEqual(rightBoundary + 1);
    expect(await trigger.boundingBox()).toEqual(triggerBefore);
    expect(await page.locator('.application-shell__topbar').boundingBox()).toEqual(topbarBefore);

    await globalInput.press('Escape');
    await expect(panel).toBeHidden();
    await expect(trigger).toHaveAttribute('aria-expanded', 'false');
    await expect(trigger).toBeFocused();
};

test('the Blade shell reaches the Vue search card after one search activation', async ({ page }, testInfo) => {
    test.skip(!email || !password, 'Set E2E_EMAIL and E2E_PASSWORD to validate the authenticated search pilot.');

    const runtimeErrors: string[] = [];

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

    await login(page);
    // Phase 8 moved Home into the persistent Inertia shell; /dashboard is the
    // nearest still-Blade route for exercising the retained legacy topbar.
    await page.goto('/dashboard');
    await page.evaluate(() => {
        (window as typeof window & { __searchEntryDocument?: boolean }).__searchEntryDocument = true;
    });

    if (testInfo.project.name === 'mobile-chromium') {
        const closeNavigation = page.getByRole('button', { name: 'Close navigation' });
        const mobileSearch = page.locator('.topbar-mobile-search');
        const navigationToggle = page.locator('.topbar-sidebar-toggle');

        if (await closeNavigation.isVisible()) {
            await closeNavigation.tap();
            await expect(navigationToggle).toBeFocused();
            await expect(navigationToggle).toHaveAttribute('aria-label', 'Show navigation');
            await expect(navigationToggle).not.toHaveAttribute('title', /.+/);
            await expect(page.locator('.ui-tooltip__content.is-open')).toHaveCount(0);
        }

        await expect(mobileSearch).toBeVisible();
        await mobileSearch.click();
    } else {
        const globalInput = page.locator('#global-search-input');

        await expect(globalInput).toBeVisible();
        await globalInput.focus();
        await expect(globalInput).toHaveAttribute('aria-expanded', 'true');
        await globalInput.press('Enter');
    }

    await expect(page).toHaveURL(/\/search(?:\?q=)?$/);
    await expect(page.locator('[data-frontend-root="inertia"]')).toHaveCount(1);
    await assertPersistentShell(page);
    await expect(page.getByRole('heading', { name: 'Search' })).toBeVisible();
    await expect(page.getByText('Start a search')).toBeVisible();
    expect(await page.evaluate(() => (
        window as typeof window & { __searchEntryDocument?: boolean }
    ).__searchEntryDocument)).toBeUndefined();
    expect(runtimeErrors).toEqual([]);
    await attachScreenshot(page, testInfo, `search-single-activation-${testInfo.project.name}`);
});

test('the historical Blade search keeps its portaled presets and shared actions interactive', async ({ page }, testInfo) => {
    test.skip(testInfo.project.name !== 'desktop-chromium', 'The production topbar presets only need one browser project.');
    test.skip(!email || !password, 'Set E2E_EMAIL and E2E_PASSWORD to validate the authenticated search pilot.');

    const runtimeErrors: string[] = [];

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

    await login(page);
    // Phase 8 moved Home into the persistent Inertia shell; /dashboard is the
    // nearest still-Blade route for exercising the retained legacy topbar.
    await page.goto('/dashboard');

    const input = page.locator('#global-search-input');
    const panel = page.locator('#global-search-panel');

    await input.focus();
    await expect(panel).toBeVisible();
    await expect(input).toHaveAttribute('aria-expanded', 'true');
    await expect.poll(() => panel.evaluate((element) => (
        (element.parentElement as HTMLElement | null)?.dataset.uiFloatingRoot
    ))).toBe('popover');

    await expect(panel.getByText('Open full search', { exact: true })).toHaveCount(0);
    await expect(panel.getByText('Create new fund', { exact: true })).toBeVisible();
    await expect(panel.getByText('Create new GP', { exact: true })).toBeVisible();
    await expect(panel.getByText('Create new investor', { exact: true })).toBeVisible();
    await expect(panel.locator('a[href$="/gps/create"]')).toBeVisible();
    await expect(panel.locator('a[href$="/investors/create"]')).toBeVisible();

    for (const query of ['fund', 'gp', 'investor']) {
        await panel.locator(`[data-search-chip="${query}"]`).click();
        await expect(input).toHaveValue(query);
        await expect(input).toBeFocused();
        await expect(input).toHaveAttribute('aria-expanded', 'true');
    }

    await attachScreenshot(page, testInfo, 'blade-global-search-shared-presets');

    await input.fill('');
    await input.press('Escape');
    await expect(panel).not.toHaveClass(/is-open/);
    await expect(panel).toHaveAttribute('inert', '');
    expect(runtimeErrors).toEqual([]);
});

test('phase six search preserves its Vue shell, state, history, errors, accessibility and native exits', async ({ page }, testInfo) => {
    test.skip(!email || !password, 'Set E2E_EMAIL and E2E_PASSWORD to validate the authenticated search pilot.');

    const consoleProblems: BrowserProblem[] = [];
    page.on('console', (message) => {
        if (message.type() === 'error' || message.type() === 'warning') {
            consoleProblems.push({
                type: message.type(),
                text: message.text(),
                url: message.location().url,
            });
        }
    });
    page.on('pageerror', (error) => consoleProblems.push({
        type: 'pageerror',
        text: error.message,
        url: '',
    }));

    await installPerformanceObservers(page);
    await login(page);
    // Phase 8 moved Home into the persistent Inertia shell; /dashboard is the
    // nearest still-Blade route for exercising the retained legacy topbar.
    await page.goto('/dashboard');
    await page.evaluate(() => {
        window.localStorage.removeItem('kview_investor.sidebar.hidden');
    });

    const bladeMarker = await page.evaluate(() => {
        (window as typeof window & { __searchPilotMarker?: string }).__searchPilotMarker = crypto.randomUUID();

        return (window as typeof window & { __searchPilotMarker: string }).__searchPilotMarker;
    });
    const entrySearch = page.locator('form[action$="/search"]:visible').first();

    await expect(entrySearch).toBeVisible();
    await entrySearch.locator('input[name="q"]').fill('');
    await entrySearch.locator('input[name="q"]').press('Enter');

    await expect(page).toHaveURL(/\/search(?:\?q=)?$/);
    await expect(page.locator('[data-frontend-root="inertia"]')).toHaveCount(1);
    await assertPersistentShell(page);
    await expect(page.getByText('Start a search')).toBeVisible();
    expect(await page.evaluate(() => (
        window as typeof window & { __searchPilotMarker?: string }
    ).__searchPilotMarker)).not.toBe(bladeMarker);

    const coldSamples: ColdMetrics[] = [];

    for (let index = 0; index < 3; index += 1) {
        await clearBrowserCache(page);
        await page.goto('/search?q=Demo');
        await expect(page.getByRole('region', { name: 'Search results' })).toBeVisible();
        await expect(page.locator('.search-result-group__link')).not.toHaveCount(0);
        await assertPersistentShell(page);
        await assertTopbarDoesNotOverlap(page);
        await assertSearchCardFillsSection(page);
        await assertSearchCardUsesApplicationDensity(page);
        await page.evaluate(() => new Promise<void>((resolve) => {
            requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
        }));
        coldSamples.push(await collectColdMetrics(page));
    }

    const coldMetrics = summarizeColdMetrics(coldSamples);
    await attachJson(testInfo, `search-cold-${testInfo.project.name}`, {
        samples: coldSamples,
        median: coldMetrics,
    });
    await attachScreenshot(page, testInfo, `search-demo-${testInfo.project.name}`);
    const staleDemoResult = (await page
        .locator('.search-result-group__link')
        .first()
        .innerText()).trim();

    expect(staleDemoResult).not.toBe('');

    const inertiaMarker = await page.evaluate(() => {
        (window as typeof window & { __searchPilotMarker?: string }).__searchPilotMarker = crypto.randomUUID();

        return (window as typeof window & { __searchPilotMarker: string }).__searchPilotMarker;
    });
    const shellMarker = await page.locator('.application-shell').evaluate((shell) => {
        const marker = crypto.randomUUID();

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

        return marker;
    });

    const scrollStyle = await page.addStyleTag({ content: '.search-page { min-height: 1800px !important; }' });
    const scrollRegion = page.locator('#application-content');
    await scrollRegion.evaluate((element) => element.scrollTo(0, 500));
    await expect.poll(() => scrollRegion.evaluate((element) => element.scrollTop)).toBeGreaterThan(300);

    let delayed = false;
    let releaseDelayedVisit = (): void => {};
    const delayedVisitGate = new Promise<void>((resolve) => {
        releaseDelayedVisit = resolve;
    });
    await page.route('**/search?*', async (route) => {
        const request = route.request();
        const query = new URL(request.url()).searchParams.get('q');

        if (request.headers()['x-inertia'] === 'true' && query === 'Northstar' && !delayed) {
            delayed = true;
            await delayedVisitGate;
        }

        await route.continue();
    });

    const form = page.getByRole('search', { name: 'Search all records' });
    const input = form.getByLabel('Search');

    await input.fill('  Northstar  ');
    await input.focus();
    const delayedWarmStartedAt = await resetWarmMetrics(page);
    const scrollBeforeVisit = await scrollRegion.evaluate((element) => element.scrollTop);
    expect(scrollBeforeVisit).toBeGreaterThan(100);
    await input.press('Enter');

    await expect(form).toHaveAttribute('aria-busy', 'true');
    await expect(page.locator('#application-content')).toHaveAttribute('aria-busy', 'true');
    await expect(page.locator('.search-page__status')).toContainText('Searching all records');
    await expect(input).toBeFocused();
    await page.waitForTimeout(180);
    await expect(page.locator('#application-content')).toHaveAttribute('aria-busy', 'true');
    await expect(page.locator('.application-shell__navigation-skeleton')).toHaveCount(0);
    // While the delayed visit is pending, keep whichever real Demo result
    // was rendered by the current dataset. A named fixture is brittle once
    // the seeded corpus grows beyond the first result page.
    await expect(page.getByRole('region', { name: 'Search results' })).toContainText(staleDemoResult);
    releaseDelayedVisit();
    await expect(page).toHaveURL(/\/search\?q=Northstar$/);
    await expect(page.getByRole('region', { name: 'Search results' })).toContainText('Demo Northstar Partners');
    await expect(form).not.toHaveAttribute('aria-busy', 'true');
    await expect(page.locator('.search-page__status')).toContainText(/results? found for Northstar/);
    await expect(input).toBeFocused();
    await page.unroute('**/search?*');

    expect(await page.evaluate(() => (
        window as typeof window & { __searchPilotMarker?: string }
    ).__searchPilotMarker)).toBe(inertiaMarker);
    await expect.poll(() => page.locator('.application-shell').evaluate((shell) => (
        shell as HTMLElement & { __searchPilotShellMarker?: string }
    ).__searchPilotShellMarker)).toBe(shellMarker);
    await expect.poll(() => scrollRegion.evaluate((element) => element.scrollTop)).toBeLessThanOrEqual(1);

    const delayedWarmMetrics = await collectWarmMetrics(page, delayedWarmStartedAt);
    await attachJson(testInfo, `search-warm-delayed-${testInfo.project.name}`, delayedWarmMetrics);

    await page.goBack();
    await expect(page).toHaveURL(/\/search\?q=Demo$/);
    await expect(form.getByLabel('Search')).toHaveValue('Demo');
    await expect.poll(async () => Math.abs(
        await scrollRegion.evaluate((element) => element.scrollTop) - scrollBeforeVisit,
    )).toBeLessThanOrEqual(2);

    await page.goForward();
    await expect(page).toHaveURL(/\/search\?q=Northstar$/);
    await expect(form.getByLabel('Search')).toHaveValue('Northstar');
    await expect.poll(() => scrollRegion.evaluate((element) => element.scrollTop)).toBeLessThanOrEqual(1);
    await scrollStyle.evaluate((element) => element.remove());
    await attachScreenshot(page, testInfo, `search-northstar-${testInfo.project.name}`);

    await page.route('**/search?*', async (route) => {
        const request = route.request();
        const query = new URL(request.url()).searchParams.get('q');

        if (request.headers()['x-inertia'] === 'true' && query === '__network_error__') {
            await route.abort('failed');

            return;
        }

        await route.continue();
    });

    await form.getByLabel('Search').fill('__network_error__');
    await form.getByRole('button', { name: 'Search' }).click();
    await expect(page.getByRole('alert')).toContainText('Search unavailable');
    await expect(page.getByRole('alert')).toContainText('Check your connection and try again');
    await expect(form).not.toHaveAttribute('aria-busy', 'true');
    await expect(page.getByRole('region', { name: 'Search results' })).toContainText('Demo Northstar Partners');
    await page.unroute('**/search?*');

    await form.getByLabel('Search').fill('Demo');
    await form.getByRole('button', { name: 'Search' }).click();
    await expect(page).toHaveURL(/\/search\?q=Demo$/);
    await expect(page.getByRole('alert')).toHaveCount(0);
    await expect(form).not.toHaveAttribute('aria-busy', 'true');
    await expect(page.getByRole('region', { name: 'Search results' })).toBeVisible();

    const globalSearchTrigger = page.locator('.application-shell__search');
    const globalInput = page.locator('#application-search');
    await expect(globalInput).toHaveValue('Demo');

    if (testInfo.project.name === 'mobile-chromium') {
        await page.locator('.application-shell__search').click();
    } else {
        await page.keyboard.press(process.platform === 'darwin' ? 'Meta+K' : 'Control+K');
    }

    await expect(globalInput).toBeFocused();
    await expect(globalSearchTrigger).toHaveAttribute('aria-expanded', 'true');
    await expect(globalInput).toHaveAttribute('aria-expanded', 'true');
    await globalInput.fill('Northstar');
    await expect(page.locator('.application-global-search__item-title').filter({ hasText: 'Demo Northstar Partners' })).toBeVisible();
    await expect(page).toHaveURL(/\/search\?q=Demo$/);
    await expect(form.getByLabel('Search')).toHaveValue('Demo');
    await globalInput.press('Escape');
    await expect(globalSearchTrigger).toHaveAttribute('aria-expanded', 'false');
    await expect(globalInput).toHaveAttribute('aria-expanded', 'false');
    await expect(page.locator('.application-global-search__panel')).toHaveAttribute('inert', '');
    await expect(globalSearchTrigger).toBeFocused();

    await form.getByLabel('Search').fill('Northstar');
    await form.getByRole('button', { name: 'Search' }).click();
    await expect(page).toHaveURL(/\/search\?q=Northstar$/);

    await expect(globalInput).toHaveValue('Northstar');

    await expect(page.getByRole('region', { name: 'Search results' })).toContainText('Demo Northstar Partners');

    await input.focus();
    await page.keyboard.press('Tab');
    await expect(form.getByRole('button', { name: 'Search' })).toBeFocused();
    await page.keyboard.press('Tab');
    await expect(page.locator('.search-result-group__link').first()).toBeFocused();

    const accessibility = await new AxeBuilder({ page })
        .withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
        .analyze();
    await attachJson(testInfo, `search-axe-${testInfo.project.name}`, accessibility);
    await assertNoOverflow(page);

    expect(accessibility.violations).toEqual([]);
    for (const coldSample of coldSamples) {
        expect(coldSample.transferredBytes).toBeGreaterThan(0);
        // Laravel's local PHP server does not content-encode built assets. This
        // budget therefore guards the raw persistent Vue shell payload, not the
        // smaller gzip/Brotli transfer expected behind a production web server.
        expect(coldSample.transferredBytes).toBeLessThanOrEqual(localColdTransferBudgetBytes);
        expect(coldSample.lcpMs).not.toBeNull();

        if (coldSample.lcpMs !== null) {
            expect(coldSample.lcpMs).toBeLessThanOrEqual(2500);
        }

        expect(coldSample.cumulativeLayoutShift).toBeLessThanOrEqual(0.1);
        expect(coldSample.longTasksOver50Ms).toEqual([]);
    }
    expect(delayedWarmMetrics.requestCount).toBeGreaterThanOrEqual(1);
    expect(delayedWarmMetrics.requestCount).toBeLessThanOrEqual(2);
    expect(delayedWarmMetrics.transferredBytes).toBeGreaterThan(0);
    expect(delayedWarmMetrics.transferredBytes).toBeLessThanOrEqual(50_000);
    expect(delayedWarmMetrics.durationMs).toBeLessThanOrEqual(1500);
    expect(delayedWarmMetrics.inpStatus).not.toBe('unsupported');

    if (delayedWarmMetrics.inpStatus === 'measured') {
        expect(delayedWarmMetrics.inpMs).not.toBeNull();
        expect(delayedWarmMetrics.inpMs ?? Number.POSITIVE_INFINITY).toBeLessThanOrEqual(200);
    } else {
        expect(delayedWarmMetrics.inpStatus).toBe('below-16ms-threshold');
        expect(delayedWarmMetrics.inpMs).toBeNull();
    }

    expect(delayedWarmMetrics.cumulativeLayoutShift).toBeLessThanOrEqual(0.1);
    expect(delayedWarmMetrics.longTasksOver50Ms).toEqual([]);

    const naturalWarmSamples = [];

    for (const query of ['Demo', 'Northstar', 'Demo']) {
        await form.getByLabel('Search').fill(query);
        const startedAt = await resetWarmMetrics(page);
        await form.getByLabel('Search').press('Enter');
        await expect(page).toHaveURL(new RegExp(`/search\\?q=${query}$`));
        await expect(form).not.toHaveAttribute('aria-busy', 'true');
        await page.evaluate(() => new Promise<void>((resolve) => {
            requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
        }));
        naturalWarmSamples.push(await collectWarmMetrics(page, startedAt));
    }

    const durations = naturalWarmSamples
        .map((sample) => sample.durationMs)
        .sort((first, second) => first - second);
    await attachJson(testInfo, `search-warm-natural-${testInfo.project.name}`, {
        samples: naturalWarmSamples,
        medianDurationMs: durations[Math.floor(durations.length / 2)],
    });

    for (const sample of naturalWarmSamples) {
        expect(sample.requestCount).toBeGreaterThanOrEqual(1);
        expect(sample.requestCount).toBeLessThanOrEqual(2);
        expect(sample.transferredBytes).toBeGreaterThan(0);
        expect(sample.transferredBytes).toBeLessThanOrEqual(50_000);
        expect(sample.durationMs).toBeLessThanOrEqual(1000);
        expect(sample.inpStatus).not.toBe('unsupported');

        if (sample.inpStatus === 'measured') {
            expect(sample.inpMs).not.toBeNull();
            expect(sample.inpMs ?? Number.POSITIVE_INFINITY).toBeLessThanOrEqual(200);
        } else {
            expect(sample.inpStatus).toBe('below-16ms-threshold');
            expect(sample.inpMs).toBeNull();
        }

        expect(sample.cumulativeLayoutShift).toBeLessThanOrEqual(0.1);
        expect(sample.longTasksOver50Ms).toEqual([]);
    }

    if (testInfo.project.name === 'mobile-chromium') {
        const drawerToggle = page.getByRole('button', { name: 'Afficher la navigation' });

        await drawerToggle.click();
        await expect(page.getByRole('dialog', { name: 'Navigation principale' })).toBeVisible();
        await expect(page.locator('#application-content')).toHaveAttribute('inert', '');
        await page.keyboard.press('Escape');
        await expect(drawerToggle).toBeFocused();
    }

    const recordMarker = await page.evaluate(() => {
        (window as typeof window & { __searchPilotMarker?: string }).__searchPilotMarker = crypto.randomUUID();

        return (window as typeof window & { __searchPilotMarker: string }).__searchPilotMarker;
    });
    await page.locator('.search-result-group__link').first().click();
    await expect(page).toHaveURL(/\/gps\//);
    await expect(page.locator('[data-frontend-root="inertia"]')).toHaveCount(1);
    await assertPersistentShell(page);
    expect(await page.evaluate(() => (
        window as typeof window & { __searchPilotMarker?: string }
    ).__searchPilotMarker)).toBe(recordMarker);

    await page
        .locator('#application-content')
        .getByRole('link', { name: 'General Partners', exact: true })
        .click();
    await expect(page).toHaveURL(/\/gps$/);
    await expect(page.locator('[data-frontend-root="inertia"]')).toHaveCount(1);
    await expect(page.locator('.application-shell')).toHaveCount(1);
    await expect(page.locator('#top-menu, #left-menu')).toHaveCount(0);
    expect(await page.evaluate(() => (
        window as typeof window & { __searchPilotMarker?: string }
    ).__searchPilotMarker)).toBe(recordMarker);

    const expectedNetworkErrorUrls = ['/search?q=__network_error__'];
    const unexplainedConsoleProblems = consoleProblems.filter((problem) => !(
        problem.type === 'error'
        && expectedNetworkErrorUrls.some((url) => problem.url.endsWith(url))
        && problem.text.includes('Failed to load resource')
        && problem.text.includes('ERR_FAILED')
    ));
    await attachJson(testInfo, `search-console-${testInfo.project.name}`, consoleProblems);
    expect(unexplainedConsoleProblems).toEqual([]);
});

test('phase six search remains stable at constrained desktop and tablet widths', async ({ page }, testInfo) => {
    test.skip(testInfo.project.name !== 'desktop-chromium', 'Intermediate widths run once in desktop Chromium.');
    test.skip(!email || !password, 'Set E2E_EMAIL and E2E_PASSWORD to validate the authenticated search pilot.');

    await login(page);
    await page.evaluate(() => {
        window.localStorage.removeItem('kview_investor.sidebar.hidden');
    });

    for (const viewport of [
        { name: 'constrained', width: 1024, height: 900 },
        { name: 'reported-regression', width: 919, height: 790 },
        { name: 'tablet', width: 768, height: 1024 },
    ]) {
        await page.setViewportSize({ width: viewport.width, height: viewport.height });
        await page.goto('/search?q=Demo');
        await expect(page.getByRole('region', { name: 'Search results' })).toBeVisible();
        await assertPersistentShell(page);
        await assertNoOverflow(page);
        await assertTopbarDoesNotOverlap(page);
        await assertSearchCardFillsSection(page);
        await assertSearchCardUsesApplicationDensity(page);
        await assertGlobalSearchPanelMatchesTrigger(page);

        const sidebar = page.locator('#application-navigation');
        const sidebarWidth = await sidebar.evaluate((element) => element.getBoundingClientRect().width);
        expect(sidebarWidth).toBeGreaterThanOrEqual(239);
        expect(sidebarWidth).toBeLessThanOrEqual(241);
        await expect(sidebar.getByText('General Partners', { exact: true })).toBeVisible();

        if (viewport.width === 919) {
            await page.getByRole('button', { name: 'Masquer la navigation' }).click();
            await expect(sidebar).toHaveAttribute('aria-hidden', 'true');
            await expect.poll(() => sidebar.evaluate((element) => element.getBoundingClientRect().width)).toBeLessThanOrEqual(1);
            await expect(sidebar).toBeHidden();
            await page.getByRole('button', { name: 'Afficher la navigation' }).click();
            await expect(sidebar).not.toHaveAttribute('aria-hidden', 'true');
            await expect.poll(() => sidebar.evaluate((element) => element.getBoundingClientRect().width)).toBeGreaterThanOrEqual(239);
            await expect(sidebar.getByText('General Partners', { exact: true })).toBeVisible();
        }

        const accessibility = await new AxeBuilder({ page })
            .withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
            .analyze();
        await attachJson(testInfo, `search-axe-${viewport.name}`, accessibility);
        expect(accessibility.violations).toEqual([]);

        const geometry = await page.locator('.search-page__group').evaluateAll((groups) => (
            groups.map((group) => {
                const bounds = group.getBoundingClientRect();

                return { left: Math.round(bounds.left), top: Math.round(bounds.top) };
            })
        ));

        expect(geometry).toHaveLength(3);
        expect(geometry[1]?.left).toBe(geometry[0]?.left);
        expect(geometry[1]?.top).toBeGreaterThan(geometry[0]?.top ?? 0);
        await attachScreenshot(page, testInfo, `search-${viewport.name}`);
    }
});
