import { expect, test, type Page } from '@playwright/test';

import {
  getShellRouteByPageId,
  resolveShellNavPage,
  shellRouteManifest,
  type ShellPageId,
} from '../src/platform/shell/route-manifest';

async function selectProfile(page: Page, baseURL: string, profileId = 1) {
  const response = await page.request.post(new URL('/api/profiles/select', baseURL).toString(), {
    data: { profile_id: profileId },
  });

  expect(response.ok()).toBe(true);
}

async function waitForShellRoute(page: Page, pageId: string) {
  const route = getShellRouteByPageId(pageId as ShellPageId);

  if (route?.kind === 'react') {
    await expect
      .poll(async () => page.evaluate(() => document.querySelector('.page.active')?.id ?? ''), {
        timeout: 15000,
      })
      .toBe('webui-react-root');
    return;
  }

  await expect
    .poll(async () => page.evaluate(() => document.querySelector('.page.active')?.id ?? ''))
    .toBe(`${pageId}-page`);
}

function getExpectedNavPage(pageId: ShellPageId): string {
  return resolveShellNavPage(pageId);
}

async function expectNavHighlight(page: Page, pageId: ShellPageId) {
  const navPage = getExpectedNavPage(pageId);
  const activeNavPage = await page.evaluate(() => {
    return document.querySelector('.nav-button.active')?.getAttribute('data-page') ?? '';
  });

  expect(activeNavPage).toBe(navPage);
}

async function verifyIssuesRoute(page: Page) {
  const appRoot = page.locator('#webui-react-root');
  await expect(appRoot).toBeVisible();
  await expect(page.getByTestId('issues-board')).toContainText('Issues');
}

function expectedUrlPattern(path: string, pageId: ShellPageId): RegExp {
  if (pageId === 'issues') {
    return /\/issues(?:\?status=open&category=all)?$/;
  }

  if (pageId === 'stats') {
    return /\/stats(?:\?range=7d)?$/;
  }

  return new RegExp(`${path.replace('/', '\\/')}$`);
}

test('direct load activates all known shell routes', async ({ page, baseURL }) => {
  if (!baseURL) {
    test.skip();
    return;
  }

  await selectProfile(page, baseURL);

  for (const route of shellRouteManifest) {
    const routePage = await page.context().newPage();
    try {
      await routePage.goto(new URL(route.path, baseURL).toString(), {
        waitUntil: 'domcontentloaded',
      });
      await waitForShellRoute(routePage, route.pageId);
      await expect(routePage).toHaveURL(expectedUrlPattern(route.path, route.pageId));
      await expectNavHighlight(routePage, route.pageId);

      if (route.pageId === 'issues') {
        await verifyIssuesRoute(routePage);
      }
    } finally {
      await routePage.close();
    }
  }
});

test('browser history restores shell routes', async ({ page, baseURL }) => {
  if (!baseURL) {
    test.skip();
    return;
  }

  await selectProfile(page, baseURL);

  await page.goto(new URL('/discover', baseURL).toString(), { waitUntil: 'domcontentloaded' });
  await waitForShellRoute(page, 'discover');

  await page.evaluate(() => {
    (window as typeof window & { __spaNavMarker?: string }).__spaNavMarker = 'persist';
  });
  await page.getByRole('link', { name: 'Issues' }).click();
  await expect
    .poll(async () =>
      page.evaluate(
        () => (window as typeof window & { __spaNavMarker?: string }).__spaNavMarker ?? null,
      ),
    )
    .toBe('persist');
  await waitForShellRoute(page, 'issues');
  await expect(page).toHaveURL(/\/issues(?:\?status=open&category=all)?$/);

  await page.goBack();
  await waitForShellRoute(page, 'discover');
  await expect(page).toHaveURL(/\/discover$/);

  await page.goForward();
  await waitForShellRoute(page, 'issues');
  await expect(page).toHaveURL(/\/issues(?:\?status=open&category=all)?$/);
});

test('browser history leaves artist detail when going back to library', async ({
  page,
  baseURL,
}) => {
  if (!baseURL) {
    test.skip();
    return;
  }

  await selectProfile(page, baseURL);

  await page.goto(new URL('/library', baseURL).toString(), { waitUntil: 'domcontentloaded' });
  await waitForShellRoute(page, 'library');
  await expect.poll(async () => page.locator('.library-artist-card').count()).toBeGreaterThan(0);

  await page.locator('.library-artist-card').first().click();
  await waitForShellRoute(page, 'artist-detail');
  await expect(page).toHaveURL(/\/artist-detail\/library\/[^/]+$/);

  await page.goBack();
  await waitForShellRoute(page, 'library');
  await expect(page).toHaveURL(/\/library$/);
});
