import { expect, type Page } from '@playwright/test';
import {
  createFrame as _createFrame,
  addNote,
  autoFit,
  dragBetweenViewCoords,
  edgelessCommonSetup,
  getFrameTitle,
  zoomOutByKeyboard,
  zoomResetByKeyboard,
} from 'utils/actions/edgeless.js';
import {
  pressBackspace,
  pressEnter,
  pressEscape,
  type,
} from 'utils/actions/keyboard.js';
import { waitNextFrame } from 'utils/actions/misc.js';

import { test } from '../../utils/playwright.js';

const createFrame = async (
  page: Page,
  coord1: [number, number],
  coord2: [number, number]
) => {
  const frame = await _createFrame(page, coord1, coord2);
  await autoFit(page);
  return frame;
};

test.beforeEach(async ({ page }) => {
  await edgelessCommonSetup(page);
  await zoomResetByKeyboard(page);
});

const enterFrameTitleEditor = async (page: Page) => {
  const frameTitle = page.locator('affine-frame-title');
  await frameTitle.dblclick();

  const frameTitleEditor = page.locator('edgeless-frame-title-editor');
  await frameTitleEditor.waitFor({
    state: 'attached',
  });
  return frameTitleEditor;
};

test.describe('frame title rendering', () => {
  test('frame title should be displayed', async ({ page }) => {
    const frame = await createFrame(page, [50, 50], [150, 150]);

    const frameTitle = getFrameTitle(page, frame);
    await expect(frameTitle).toBeVisible();
    await expect(frameTitle).toHaveText('Frame 1');
  });

  test('frame title should be rendered on the top', async ({ page }) => {
    const frame = await createFrame(page, [50, 50], [150, 150]);

    const frameTitle = getFrameTitle(page, frame);
    await expect(frameTitle).toBeVisible();

    const frameTitleBounding = await frameTitle.boundingBox();
    expect(frameTitleBounding).not.toBeNull();
    if (!frameTitleBounding) return;

    const frameTitleCenter = [
      frameTitleBounding.x + frameTitleBounding.width / 2,
      frameTitleBounding.y + frameTitleBounding.height / 2,
    ];

    await addNote(page, '', frameTitleCenter[0], frameTitleCenter[1]);
    await pressEscape(page, 3);
    await waitNextFrame(page, 500);

    try {
      // if the frame title is rendered on the top, it should be clickable
      await frameTitle.click();
    } catch {
      expect(true, 'frame title should be rendered on the top').toBeFalsy();
    }
  });

  test('should not display frame title component when title is empty', async ({
    page,
  }) => {
    const frame = await createFrame(page, [50, 50], [150, 150]);
    await enterFrameTitleEditor(page);

    await pressBackspace(page);
    await pressEnter(page);
    const frameTitle = getFrameTitle(page, frame);
    await expect(frameTitle).toBeHidden();
  });
});

test.describe('frame title editing', () => {
  test('edit frame title by db-click title', async ({ page }) => {
    const frame = await createFrame(page, [50, 50], [150, 150]);
    const frameTitle = getFrameTitle(page, frame);

    await enterFrameTitleEditor(page);

    await type(page, 'ABC');
    await pressEnter(page);
    await expect(frameTitle).toHaveText('ABC');
  });

  test('frame title can be edited repeatedly', async ({ page }) => {
    const frame = await createFrame(page, [50, 50], [150, 150]);
    const frameTitle = getFrameTitle(page, frame);

    await enterFrameTitleEditor(page);
    await type(page, 'ABC');
    await pressEnter(page);

    await enterFrameTitleEditor(page);
    await type(page, 'DEF');
    await pressEnter(page);
    await expect(frameTitle).toHaveText('DEF');
  });

  test('edit frame after zoom', async ({ page }) => {
    const frame = await createFrame(page, [50, 50], [150, 150]);
    const frameTitle = getFrameTitle(page, frame);

    await zoomOutByKeyboard(page);
    await enterFrameTitleEditor(page);
    await type(page, 'ABC');
    await pressEnter(page);
    await expect(frameTitle).toHaveText('ABC');
  });

  test('edit frame title after drag', async ({ page }) => {
    const frame = await createFrame(page, [50, 50], [150, 150]);
    const frameTitle = getFrameTitle(page, frame);
    await dragBetweenViewCoords(page, [50 + 10, 50 + 10], [50 + 20, 50 + 20]);

    await enterFrameTitleEditor(page);
    await type(page, 'ABC');
    await pressEnter(page);
    await expect(frameTitle).toHaveText('ABC');
  });

  test('blur unmount frame editor', async ({ page }) => {
    await createFrame(page, [50, 50], [150, 150]);
    const frameTitleEditor = await enterFrameTitleEditor(page);
    await page.mouse.click(10, 10);
    await expect(frameTitleEditor).toHaveCount(0);
  });

  test('enter unmount frame editor', async ({ page }) => {
    await createFrame(page, [50, 50], [150, 150]);
    const frameTitleEditor = await enterFrameTitleEditor(page);
    await pressEnter(page);
    await expect(frameTitleEditor).toHaveCount(0);
  });
});
