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

const mod = process.platform === 'darwin' ? 'Meta' : 'Control';

test('R14.12 Visual history is canonical and section drag moves the complete subtree', async ({ page }) => {
  const workspaceName = `visual-r14-12-${Date.now()}`;
  await createBrowserWorkspace(page, { workspaceName });
  await page.getByRole('link', { name: /^main\.tex$/ }).click();

  const source = page.getByLabel('LaTeX source editor');
  const initial = [
    '\\documentclass{article}',
    '\\begin{document}',
    '\\section{One}',
    'One body.',
    '\\subsection{One A}',
    'Nested body.',
    '\\section{Two}',
    'Two body.',
    '\\end{document}',
    '',
  ].join('\n');
  await source.fill(initial);
  await source.press(`${mod}+s`);

  await page.getByRole('button', { name: 'Visual' }).click();
  const visual = page.locator('.interactive-latex-visual-editor');
  await expect(visual).toBeVisible();

  // Consecutive Visual typing should form one canonical history group. A
  // single undo restores the paragraph before the typing session.
  const twoBody = visual.locator('.interactive-visual-paragraph').filter({ hasText: 'Two body.' });
  await twoBody.click();
  await twoBody.press('End');
  await twoBody.pressSequentially(' abc');
  await expect(twoBody).toContainText('Two body. abc');
  await twoBody.press(`${mod}+z`);
  await expect(visual.locator('.interactive-visual-paragraph').filter({ hasText: 'Two body.' })).toBeVisible();
  await expect(visual).not.toContainText('Two body. abc');

  // Dragging a section must move its whole semantic subtree, including the
  // subsection and paragraphs, rather than just the heading command.
  const oneHeading = visual.locator('.interactive-visual-heading').filter({ hasText: 'One' }).first();
  const twoHeading = visual.locator('.interactive-visual-heading').filter({ hasText: 'Two' }).first();
  await oneHeading.hover();
  const dragHandle = page.getByRole('button', { name: 'Drag LaTeX block to move' });
  await expect(dragHandle).toBeVisible();
  await dragHandle.dragTo(twoHeading);

  await page.getByRole('button', { name: 'Source' }).click();
  const moved = (await source.textContent()) ?? '';
  expect(moved.indexOf('\\section{Two}')).toBeLessThan(moved.indexOf('\\section{One}'));
  expect(moved.indexOf('\\section{One}')).toBeLessThan(moved.indexOf('One body.'));
  expect(moved.indexOf('One body.')).toBeLessThan(moved.indexOf('\\subsection{One A}'));
  expect(moved.indexOf('\\subsection{One A}')).toBeLessThan(moved.indexOf('Nested body.'));

  // Unified canonical history means the move can be undone from Source too.
  await source.press(`${mod}+z`);
  const restored = (await source.textContent()) ?? '';
  expect(restored.indexOf('\\section{One}')).toBeLessThan(restored.indexOf('\\section{Two}'));
  expect(restored).toContain('Nested body.');
});
