import { expect, test, type Page, type Route } from '@playwright/test';
import { pressAppShortcut } 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) {
  await page.route('**/api/config/public', (route) =>
    json(route, 200, {
      saasEnabled: true,
      googleAuthEnabled: true,
      githubAuthEnabled: true,
      magicEmailEnabled: false,
      contactEnabled: false,
      freePlanProjectLimit: 20,
    }),
  );
  await page.route('**/api/auth/me', (route) =>
    json(route, 200, { authenticated: false }),
  );
}

async function installOpfsDirectoryPicker(page: Page, rootName: string) {
  await page.addInitScript((name) => {
    Object.defineProperty(window, 'showDirectoryPicker', {
      configurable: true,
      value: async () => {
        const opfs = await navigator.storage.getDirectory();
        return opfs.getDirectoryHandle(name, { create: true });
      },
    });
  }, rootName);
}

async function createInteractiveDoc(page: Page, projectName: string) {
  await page.getByRole('button', { name: 'New Project' }).first().click();
  const dialog = page.getByRole('dialog');
  await expect(dialog.getByLabel('Project name')).toBeVisible();
  await dialog.getByRole('radio', { name: 'Interactive Doc' }).click();
  await dialog.getByLabel('Project name').fill(projectName);
  await dialog.getByRole('button', { name: 'Create project' }).click();
  await expect(page.getByTestId('interactive-doc-project')).toBeVisible();
}

test('Projects Folder exists before entering a newly-created Interactive Doc and Projects UI uses the public navigation', async ({ page }, testInfo) => {
  test.skip(!['chromium', 'edge'].includes(testInfo.project.name), 'Local Folder sync is supported on Chrome/Edge desktop browsers.');
  const rootName = `e2e-projects-root-${Date.now()}`;
  const projectName = `e2e-interactive-doc-${Date.now()}`;
  await mockAnonymousSaas(page);
  await installOpfsDirectoryPicker(page, rootName);

  await page.goto('/projects');
  const primary = page.getByRole('navigation', { name: 'Primary' });
  for (const name of ['Features', 'Templates', 'Learn', 'Blog', 'Pricing', 'About']) {
    await expect(primary.getByRole('link', { name, exact: true })).toBeVisible();
  }

  await page.getByRole('button', { name: 'More project actions' }).click();
  await expect(page.getByText('Open External Project', { exact: true })).toHaveCount(0);
  await page.getByRole('button', { name: 'More project actions' }).click();

  await page.getByRole('button', { name: 'Storage', exact: true }).click();
  const storage = page.getByRole('dialog', { name: 'Project Storage' });
  await expect(storage.getByText('Local Folder synchronization works in Chrome and Edge desktop browsers.')).toBeVisible();
  await storage.getByRole('button', { name: 'Connect Local Folder' }).click();
  await expect(storage.getByText('Connected', { exact: true })).toBeVisible();
  await page.keyboard.press('Escape');
  await expect(storage).toBeHidden();

  await createInteractiveDoc(page, projectName);

  await expect.poll(async () => page.evaluate(async ({ rootName: folder, projectName: project }) => {
    try {
      const opfs = await navigator.storage.getDirectory();
      const root = await opfs.getDirectoryHandle(folder);
      const projectDir = await root.getDirectoryHandle(project);
      const metadata = await projectDir.getDirectoryHandle('.learnitive');
      await metadata.getFileHandle('project.json');
      await projectDir.getFileHandle('document.interactive.json');
      return true;
    } catch {
      return false;
    }
  }, { rootName, projectName })).toBe(true);

  await expect(page).toHaveURL(new RegExp(`${projectName}.*document\\.interactive\\.json`, 'iu'));
});

test('Interactive Doc uses stable Editor.js controls, autosave UI, unbranded preview and block select-all', async ({ page }) => {
  const projectName = `e2e-doc-editor-${Date.now()}`;
  await mockAnonymousSaas(page);
  await page.goto('/projects');
  await createInteractiveDoc(page, projectName);

  const editor = page.locator('.interactive-content-editorjs-shell');
  await expect(editor).toBeVisible();
  await expect(editor.locator('.interactive-content-block-drag-handle')).toHaveCount(0);
  await expect(page.getByRole('button', { name: 'Save', exact: true })).toHaveCount(0);

  const paragraph = editor.locator('.ce-paragraph').first();
  await expect(paragraph).toBeVisible();
  await paragraph.click();
  await pressAppShortcut(page, 'a');
  await expect(editor.getByRole('toolbar', { name: 'Selected blocks' })).toContainText('1 selected');
  await editor.getByRole('button', { name: 'Clear' }).click();

  await paragraph.click();
  await page.keyboard.type('/');
  const listChoice = page.getByText('List', { exact: true }).last();
  await expect(listChoice).toBeVisible();
  await listChoice.click();
  const list = editor.locator('.interactive-content-structured-list').first();
  await expect(list).toBeVisible();
  await expect(list.getByRole('button', { name: 'Indent item' })).toBeVisible();
  await expect(list.getByRole('button', { name: 'Outdent item' })).toBeVisible();
  await expect(list.getByRole('button', { name: 'Remove item' })).toBeVisible();
  await expect(list.getByRole('button', { name: '+ Add item' })).toBeVisible();

  await page.getByRole('button', { name: 'Preview' }).click();
  const preview = page.locator('.interactive-doc-document-shell').first();
  await expect(preview).toBeVisible();
  await expect(preview.getByText('Learnitive', { exact: true })).toHaveCount(0);
});


test('new Interactive Doc code blocks start display-only', async ({ page }) => {
  const projectName = `e2e-doc-code-${Date.now()}`;
  await mockAnonymousSaas(page);
  await page.goto('/projects');
  await createInteractiveDoc(page, projectName);

  const editor = page.locator('.interactive-content-editorjs-shell');
  const paragraph = editor.locator('.ce-paragraph').first();
  await paragraph.click();
  await page.keyboard.type('```');
  await page.keyboard.press('Enter');

  await expect(editor.getByText('Code · display only', { exact: true })).toBeVisible();
  await editor.getByText('Code settings', { exact: true }).click();
  await expect(editor.getByRole('checkbox', { name: /Runnable Code/u })).not.toBeChecked();
});
