import { expect, test, type Page, type Route } from '@playwright/test';
import { createBrowserWorkspace } from './common';

function json(route: Route, status: number, body: unknown) {
  return route.fulfill({
    status,
    contentType: 'application/json',
    body: JSON.stringify(body),
  });
}

async function mockAnonymousSaas(page: Page, getProjectLimit: () => number) {
  await page.route('**/api/config/public', (route) =>
    json(route, 200, {
      saasEnabled: true,
      googleAuthEnabled: true,
      githubAuthEnabled: true,
      magicEmailEnabled: false,
      contactEnabled: false,
      shopUrl: '',
      freePlanProjectLimit: getProjectLimit(),
    }),
  );
  await page.route('**/api/auth/me', (route) =>
    json(route, 200, { authenticated: false }),
  );
}

test('anonymous Compile opens provider-aware sign in and preserves the exact project route', async ({ page }) => {
  await mockAnonymousSaas(page, () => 5);
  const workspaceName = `compile-auth-${Date.now()}`;
  await createBrowserWorkspace(page, { workspaceName });

  const returnTo = await page.evaluate(
    () => `${window.location.pathname}${window.location.search}${window.location.hash}`,
  );
  await expect(page.locator('a.interactive-editor-brand')).toHaveAttribute('href', '/projects');

  await page.getByRole('button', { name: 'Compile project' }).click();
  const dialog = page.getByRole('dialog').filter({ hasText: 'Sign in' });
  await expect(dialog).toBeVisible();
  await expect(dialog.getByRole('heading', { name: 'Sign in', exact: true })).toBeVisible();
  await expect(dialog.getByRole('link', { name: 'Continue with Google' })).toHaveAttribute(
    'href',
    `/api/auth/google?returnTo=${encodeURIComponent(returnTo)}`,
  );
  await expect(dialog.getByRole('link', { name: 'Continue with GitHub' })).toHaveAttribute(
    'href',
    `/api/auth/github?returnTo=${encodeURIComponent(returnTo)}`,
  );
  await expect(page).toHaveURL(new RegExp(`${workspaceName}.*main\\.tex`, 'u'));

  await dialog.getByRole('button', { name: 'Continue without an account' }).click();
  await expect(dialog).toBeHidden();
  await expect(page).toHaveURL(new RegExp(`${workspaceName}.*main\\.tex`, 'u'));
});

test('active-file bold moves away from main.tex when another file becomes active', async ({ page }) => {
  await mockAnonymousSaas(page, () => 5);
  const workspaceName = `active-file-${Date.now()}`;
  await createBrowserWorkspace(page, { workspaceName });

  const explorer = page.getByTestId('interactive-file-explorer');
  await explorer.getByRole('button', { name: 'New File' }).click();
  const createDialog = page.getByRole('dialog', { name: 'Create Project File' });
  await createDialog.getByLabel('File name').fill('chapter.tex');
  await createDialog.getByRole('button', { name: 'Create' }).click();

  const main = explorer.getByRole('treeitem', { name: /^main\.tex$/u });
  const chapter = explorer.getByRole('treeitem', { name: /^chapter\.tex$/u });
  await expect(chapter).toHaveAttribute('aria-selected', 'true');
  await expect(main).not.toHaveAttribute('aria-selected', 'true');
  await expect.poll(() => chapter.evaluate((node) => getComputedStyle(node).fontWeight)).toBe('700');
  await expect.poll(() => main.evaluate((node) => getComputedStyle(node).fontWeight)).not.toBe('700');

  const tabs = page.getByTestId('interactive-editor-file-tabs');
  await expect(tabs.locator('[data-editor-tab-active="true"]')).toContainText('chapter.tex');
  await expect.poll(() => tabs.locator('[data-editor-tab-active="false"]').filter({ hasText: 'main.tex' }).evaluate((node) => getComputedStyle(node).fontWeight)).toBe('400');

  await main.click();
  await expect(main).toHaveAttribute('aria-selected', 'true');
  await expect(chapter).not.toHaveAttribute('aria-selected', 'true');
  await expect.poll(() => main.evaluate((node) => getComputedStyle(node).fontWeight)).toBe('700');
  await expect.poll(() => chapter.evaluate((node) => getComputedStyle(node).fontWeight)).not.toBe('700');
});

test('Free project usage is danger-colored when the browser project count reaches the limit', async ({ page }) => {
  let limit = 5;
  await mockAnonymousSaas(page, () => limit);
  await createBrowserWorkspace(page, { workspaceName: `limit-a-${Date.now()}` });
  await createBrowserWorkspace(page, { workspaceName: `limit-b-${Date.now()}` });

  limit = 2;
  await page.goto('/projects');
  await page.reload({ waitUntil: 'domcontentloaded' });

  const usage = page.locator('p.text-destructive').filter({ hasText: '2 of 2 projects · Free limit' });
  await expect(usage).toBeVisible();
  await expect(page.getByRole('button', { name: 'New Project' })).toBeDisabled();
});
