import type { Padding, SceneElement, Viewport } from './domino'

/**
 * 计算元素移动到安全视野内的 Viewport 变换 (纯算法，无 DOM 依赖)
 */
export function calculateScrollIntoViewTransform(
  element: SceneElement,
  viewport: Viewport,
  containerRect: { width: number; height: number },
  padding: Required<Padding>,
  options: {
    force?: boolean
    block?: 'start' | 'center' | 'end' | 'nearest'
    inline?: 'start' | 'center' | 'end' | 'nearest'
    targetScale?: number
  },
): Viewport | null {
  const { x: currentX, y: currentY, scale: currentScale } = viewport
  const { force, block = 'nearest', inline = 'nearest', targetScale } = options
  const scale = targetScale ?? currentScale

  // 计算安全区域
  const safeLeft = padding.left
  const safeTop = padding.top
  const safeRight = containerRect.width - padding.right
  const safeBottom = containerRect.height - padding.bottom
  const safeWidth = safeRight - safeLeft
  const safeHeight = safeBottom - safeTop

  // 元素即时边界
  const elW = element.width * scale
  const elH = element.height * scale
  const elLeft = element.x * scale + currentX
  const elRight = elLeft + elW
  const elTop = element.y * scale + currentY
  const elBottom = elTop + elH

  const isXOutOfView = force || elLeft < safeLeft || elRight > safeRight
  const isYOutOfView = force || elTop < safeTop || elBottom > safeBottom

  let nextX = currentX
  let nextY = currentY

  if (isXOutOfView) {
    if (inline === 'center') {
      nextX = safeLeft + (safeWidth - elW) / 2 - element.x * scale
    } else if (
      inline === 'start' ||
      (inline === 'nearest' && elLeft < safeLeft)
    ) {
      nextX = safeLeft - element.x * scale
    } else if (
      inline === 'end' ||
      (inline === 'nearest' && elRight > safeRight)
    ) {
      nextX = safeRight - elW - element.x * scale
    }
  }

  if (isYOutOfView) {
    if (block === 'center') {
      nextY = safeTop + (safeHeight - elH) / 2 - element.y * scale
    } else if (block === 'start' || (block === 'nearest' && elTop < safeTop)) {
      nextY = safeTop - element.y * scale
    } else if (
      block === 'end' ||
      (block === 'nearest' && elBottom > safeBottom)
    ) {
      nextY = safeBottom - elH - element.y * scale
    }
  }

  const hasChange =
    nextX !== currentX ||
    nextY !== currentY ||
    (targetScale !== undefined && targetScale !== currentScale)

  return hasChange ? { x: nextX, y: nextY, scale } : null
}

/**
 * 计算适应屏幕的 Viewport 变换 (纯算法，无 DOM 依赖)
 */
export function calculateZoomToFitTransform(
  elements: SceneElement[],
  containerRect: { width: number; height: number },
  padding: Required<Padding>,
): Viewport | null {
  if (elements.length === 0) return null

  let minX = Infinity
  let minY = Infinity
  let maxX = -Infinity
  let maxY = -Infinity

  elements.forEach(el => {
    minX = Math.min(minX, el.x)
    minY = Math.min(minY, el.y)
    maxX = Math.max(maxX, el.x + el.width)
    maxY = Math.max(maxY, el.y + el.height)
  })

  const contentWidth = maxX - minX
  const contentHeight = maxY - minY

  const safeWidth = containerRect.width - padding.left - padding.right
  const safeHeight = containerRect.height - padding.top - padding.bottom

  if (safeWidth <= 0 || safeHeight <= 0) return null

  const scaleX = safeWidth / contentWidth
  const scaleY = safeHeight / contentHeight
  const targetScale = Math.max(
    0.02,
    Math.min(4, Math.min(scaleX, scaleY) * 0.95),
  )

  const nextX =
    padding.left +
    (safeWidth - contentWidth * targetScale) / 2 -
    minX * targetScale
  const nextY =
    padding.top +
    (safeHeight - contentHeight * targetScale) / 2 -
    minY * targetScale

  return { x: nextX, y: nextY, scale: targetScale }
}

/**
 * 计算元素的绝对位置和旋转 (世界坐标)
 */
export function getElementWorldRect(
  element: SceneElement,
  elements: Record<string, SceneElement>,
) {
  let x = element.x
  let y = element.y
  let rotation = element.rotation || 0
  let curr = element

  const visited = new Set<string>([element.id])

  while (curr.parentId) {
    if (visited.has(curr.parentId)) {
      console.warn(
        'Circular dependency detected in element tree',
        curr.parentId,
      )
      break
    }

    const parent = elements[curr.parentId]
    if (!parent) break

    x += parent.x
    y += parent.y
    rotation += parent.rotation || 0

    visited.add(curr.parentId)
    curr = parent
  }

  return {
    x,
    y,
    width: element.width,
    height: element.height,
    rotation,
  }
}

/**
 * 计算一组元素的包围盒 (考虑旋转和父级偏移)
 */
export function getElementsBounds(
  ids: string[],
  elements: Record<string, SceneElement>,
) {
  if (ids.length === 0) return null

  let minX = Infinity
  let minY = Infinity
  let maxX = -Infinity
  let maxY = -Infinity

  ids.forEach(id => {
    const rawEl = elements[id]
    if (!rawEl) return

    const el = getElementWorldRect(rawEl, elements)

    const rad = (el.rotation * Math.PI) / 180
    const cx = el.x + el.width / 2
    const cy = el.y + el.height / 2
    const corners = [
      [-el.width / 2, -el.height / 2],
      [el.width / 2, -el.height / 2],
      [el.width / 2, el.height / 2],
      [-el.width / 2, el.height / 2],
    ]

    corners.forEach(([px, py]) => {
      const rx = px * Math.cos(rad) - py * Math.sin(rad)
      const ry = px * Math.sin(rad) + py * Math.cos(rad)
      const wx = rx + cx
      const wy = ry + cy
      minX = Math.min(minX, wx)
      minY = Math.min(minY, wy)
      maxX = Math.max(maxX, wx)
      maxY = Math.max(maxY, wy)
    })
  })

  if (minX === Infinity) return null

  return {
    left: minX,
    top: minY,
    width: maxX - minX,
    height: maxY - minY,
    right: maxX,
    bottom: maxY,
    centerX: (minX + maxX) / 2,
    centerY: (minY + maxY) / 2,
  }
}
