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

import { CanvasHelper } from '#tests/helpers/canvas'

async function clickCanvas(page: Page, x: number, y: number) {
  const canvas = page.getByTestId('canvas-element')
  const box = await canvas.boundingBox()
  if (!box) throw new Error('Canvas has no bounding box')
  await page.mouse.click(box.x + x, box.y + y)
}

async function dblclickCanvas(page: Page, x: number, y: number) {
  const canvas = page.getByTestId('canvas-element')
  const box = await canvas.boundingBox()
  if (!box) throw new Error('Canvas has no bounding box')
  await canvas.dispatchEvent('dblclick', {
    clientX: box.x + x,
    clientY: box.y + y,
    bubbles: true,
    cancelable: true
  })
}

async function setupAutoLayoutFrame(page: Page) {
  return page.evaluate(() => {
    const store = window.openPencil?.getStore?.()
    if (!store) throw new Error('OpenPencil store not initialized')

    store.state.panX = 0
    store.state.panY = 0
    store.state.zoom = 1

    const pageId = store.state.currentPageId
    const frame = store.graph.createNode('FRAME', pageId, {
      name: 'Padding editor frame',
      x: 160,
      y: 120,
      width: 280,
      height: 160,
      layoutMode: 'VERTICAL',
      itemSpacing: 8,
      paddingTop: 20,
      paddingRight: 20,
      paddingBottom: 20,
      paddingLeft: 20
    })
    store.graph.createNode('RECTANGLE', frame.id, {
      name: 'Child',
      x: 180,
      y: 140,
      width: 120,
      height: 40
    })
    store.select([frame.id])
    store.requestRender()
    return frame.id
  })
}

async function framePaddingTop(page: Page, frameId: string) {
  return page.evaluate((id) => {
    const store = window.openPencil?.getStore?.()
    if (!store) throw new Error('OpenPencil store not initialized')
    return store.graph.getNode(id)?.paddingTop ?? null
  }, frameId)
}

test('double-clicking an auto-layout padding handle opens a scrub editor', async ({ page }) => {
  await page.goto('/')
  const canvas = new CanvasHelper(page)
  await canvas.waitForInit()
  await canvas.clearCanvas()

  const frameId = await setupAutoLayoutFrame(page)
  await canvas.waitForRender()

  await canvas.hover(300, 130)
  await dblclickCanvas(page, 300, 130)

  const editor = page.getByTestId('auto-layout-padding-editor')
  await expect(editor).toBeVisible()

  await canvas.dragScrubInput(editor.getByTestId('auto-layout-padding-input'), 40)

  await expect(editor).toHaveCount(0)
  const changedPadding = await framePaddingTop(page, frameId)
  expect(changedPadding).not.toBeNull()
  expect(changedPadding).toBeGreaterThan(20)

  await canvas.undo()
  expect(await framePaddingTop(page, frameId)).toBe(20)
  canvas.assertNoErrors()
})

test('clicking the canvas closes the auto-layout padding editor', async ({ page }) => {
  await page.goto('/')
  const canvas = new CanvasHelper(page)
  await canvas.waitForInit()
  await canvas.clearCanvas()

  await setupAutoLayoutFrame(page)
  await canvas.waitForRender()

  await canvas.hover(300, 130)
  await dblclickCanvas(page, 300, 130)
  const editor = page.getByTestId('auto-layout-padding-editor')
  await expect(editor).toBeVisible()

  await clickCanvas(page, 80, 80)
  await expect(editor).toHaveCount(0)
  canvas.assertNoErrors()
})

test('auto-layout padding editor follows canvas pan while open', async ({ page }) => {
  await page.goto('/')
  const canvas = new CanvasHelper(page)
  await canvas.waitForInit()
  await canvas.clearCanvas()

  await setupAutoLayoutFrame(page)
  await canvas.waitForRender()

  await canvas.hover(300, 130)
  await dblclickCanvas(page, 300, 130)
  const editor = page.getByTestId('auto-layout-padding-editor')
  await expect(editor).toBeVisible()
  const before = await editor.boundingBox()
  if (!before) throw new Error('Padding editor has no bounding box')

  await page.evaluate(() => {
    const store = window.openPencil?.getStore?.()
    if (!store) throw new Error('OpenPencil store not initialized')
    store.pan(40, 0)
  })
  await canvas.waitForRender()

  const after = await editor.boundingBox()
  if (!after) throw new Error('Padding editor has no bounding box after pan')
  expect(after.x).toBeGreaterThan(before.x + 20)
  canvas.assertNoErrors()
})
