import { describe, it, expect } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { WysiwygBuilderPage } from '@/components/wysiwyg/WysiwygBuilderPage'

function getXY(el: HTMLElement) {
  const style = el.getAttribute('style') || ''
  const m = { left: /left:\s*(\d+)px/, top: /top:\s*(\d+)px/ }
  const left = Number((style.match(m.left)?.[1]) || '0')
  const top = Number((style.match(m.top)?.[1]) || '0')
  return { left, top }
}

function getRotate(el: HTMLElement) {
  const style = el.getAttribute('style') || ''
  const m = /rotate\(([-\d.]+)deg\)/
  const v = Number((style.match(m)?.[1]) || '0')
  return v
}

describe('WYSIWYG - group actions drag/resize/rotate with snapping', () => {
  it('drags two selected objects together with 8px snapping', async () => {
    render(<WysiwygBuilderPage />)
    // add two texts
    const addText = () => fireEvent.click(screen.getByRole('button', { name: /^Add Text$/i }))
    addText()
    addText()
    const objs = await screen.findAllByTestId(/obj-text-/)
    const a = objs[0]
    const b = objs[1]

    // select both (click first then shift-click second)
    fireEvent.mouseDown(a, { clientX: 60, clientY: 60 })
    fireEvent.mouseUp(a)
    fireEvent.mouseDown(b, { clientX: 80, clientY: 80, shiftKey: true })
    // wait until selection reflects two items
    await screen.findByText(/선택 2개/)

    const canvas = screen.getByTestId('wysiwyg-canvas')
    // drag second (selected) by ~13, expect snap to +16
    fireEvent.mouseDown(b, { clientX: 120, clientY: 120 })
    fireEvent.mouseMove(canvas, { clientX: 133, clientY: 133 })
    fireEvent.mouseUp(canvas)

    await waitFor(() => {
      const xyA = getXY(a)
      const xyB = getXY(b)
      expect(xyA.left).toBe(76)
      expect(xyA.top).toBe(76)
      expect(xyB.left).toBe(76)
      expect(xyB.top).toBe(76)
    })
  })

  it('resizes group from east handle; both widths increase with snapping', async () => {
    render(<WysiwygBuilderPage />)
    const addText = () => fireEvent.click(screen.getByRole('button', { name: /^Add Text$/i }))
    addText()
    addText()
    const objs = await screen.findAllByTestId(/obj-text-/)
    const a = objs[0]
    const b = objs[1]

    // select both
    fireEvent.mouseDown(a, { clientX: 60, clientY: 60 })
    fireEvent.mouseUp(a)
    fireEvent.mouseDown(b, { clientX: 80, clientY: 80, shiftKey: true })

    // drag east handle of second by ~13 -> snap width +16
    const idB = (b.getAttribute('data-testid') || '').replace('obj-', '')
    const handleE = await screen.findByTestId(`resize-handle-e-${idB}`)
    fireEvent.mouseDown(handleE, { clientX: 180, clientY: 80 })
    const canvas = screen.getByTestId('wysiwyg-canvas')
    fireEvent.mouseMove(canvas, { clientX: 193, clientY: 80 })
    fireEvent.mouseUp(canvas)

    // widths reflected in inline style
    const styleA = a.getAttribute('style') || ''
    const styleB = b.getAttribute('style') || ''
    const wA = Number((styleA.match(/width:\s*(\d+)px/)?.[1]) || '0')
    const wB = Number((styleB.match(/width:\s*(\d+)px/)?.[1]) || '0')
    expect(wA).toBeGreaterThanOrEqual(176) // initial 160 -> +16
    expect(wB).toBeGreaterThanOrEqual(176)
  })

  it('rotates group with 15deg snapping (no shift)', async () => {
    render(<WysiwygBuilderPage />)
    const addText = () => fireEvent.click(screen.getByRole('button', { name: /^Add Text$/i }))
    addText()
    addText()
    const objs = await screen.findAllByTestId(/obj-text-/)
    const a = objs[0]
    const b = objs[1]

    // select both
    fireEvent.mouseDown(a)
    fireEvent.mouseUp(a)
    fireEvent.mouseDown(b, { shiftKey: true })
    fireEvent.mouseUp(b)

    const idB2 = (b.getAttribute('data-testid') || '').replace('obj-', '')
    const rotateHandle = await screen.findByTestId(`rotate-handle-${idB2}`)
    fireEvent.mouseDown(rotateHandle, { clientX: 100, clientY: 10 })
    const canvas = screen.getByTestId('wysiwyg-canvas')
    fireEvent.mouseMove(canvas, { clientX: 130, clientY: 10 }) // +30 -> snap 30 (15 step)
    fireEvent.mouseUp(canvas)

    const rA = getRotate(a)
    const rB = getRotate(b)
    expect(rA).toBe(30)
    expect(rB).toBe(30)
  })
})
