import type {
  SceneElement,
  TextElement,
  ImageElement,
  PlaceholderElement,
} from '../domino'

interface BoundingBox {
  x: number
  y: number
  width: number
  height: number
  fontSize?: number
}

export function calculateResize(
  id: string,
  startEl: BoundingBox,
  el: SceneElement | PlaceholderElement,
  handle: string,
  totalWdx: number,
  totalWdy: number,
  scale: number,
  shiftKey: boolean,
  altKey: boolean,
) {
  const rad = ((el.rotation || 0) * Math.PI) / 180
  const cos = Math.cos(rad)
  const sin = Math.sin(rad)

  const ldx = totalWdx * cos + totalWdy * sin
  const ldy = -totalWdx * sin + totalWdy * cos

  let isProportional = el.lockAspectRatio !== false
  const isSideHandle =
    handle === 'ml' || handle === 'mr' || handle === 'mt' || handle === 'mb'
  if (isSideHandle) {
    isProportional = false
  }

  if (shiftKey) {
    isProportional = !isProportional
  }
  const ratio = startEl.width / (startEl.height || 1)

  let mw = 0
  let mh = 0
  let fx = 0
  let fy = 0

  if (handle === 'nw') {
    mw = -1
    mh = -1
    fx = 0.5
    fy = 0.5
  } else if (handle === 'ne') {
    mw = 1
    mh = -1
    fx = -0.5
    fy = 0.5
  } else if (handle === 'sw') {
    mw = -1
    mh = 1
    fx = 0.5
    fy = -0.5
  } else if (handle === 'se') {
    mw = 1
    mh = 1
    fx = -0.5
    fy = -0.5
  } else if (handle === 'ml') {
    mw = -1
    mh = 0
    fx = 0.5
    fy = 0
  } else if (handle === 'mr') {
    mw = 1
    mh = 0
    fx = -0.5
    fy = 0
  } else if (handle === 'mt') {
    mw = 0
    mh = -1
    fx = 0
    fy = 0.5
  } else if (handle === 'mb') {
    mw = 0
    mh = 1
    fx = 0
    fy = -0.5
  }

  let targetW = startEl.width + mw * ldx
  let targetH = startEl.height + mh * ldy

  if (isProportional) {
    if (!isSideHandle) {
      if (Math.abs(mw * ldx) > Math.abs(mh * ldy)) {
        targetH = targetW / ratio
      } else {
        targetW = targetH * ratio
      }
    }
  }

  let isSnappedToOriginal = false
  if (el.type === 'image' && !altKey) {
    const img = el as ImageElement
    if (img.originalWidth && img.originalHeight) {
      const snapThreshold = 5 / scale
      const distW = Math.abs(targetW - img.originalWidth)
      const distH = Math.abs(targetH - img.originalHeight)
      if (distW < snapThreshold || distH < snapThreshold) {
        targetW = img.originalWidth
        targetH = img.originalHeight
        isSnappedToOriginal = true
      }
    }
  }

  const minSize = 20
  if (targetW < minSize) targetW = minSize
  if (targetH < minSize) targetH = minSize
  if (isProportional) {
    if (targetW / targetH > ratio) {
      targetW = targetH * ratio
    } else {
      targetH = targetW / ratio
    }
  }

  const startCx = startEl.x + startEl.width / 2
  const startCy = startEl.y + startEl.height / 2

  const fpx = startCx + (fx * startEl.width * cos - fy * startEl.height * sin)
  const fpy = startCy + (fx * startEl.width * sin + fy * startEl.height * cos)

  const ncx = fpx - (fx * targetW * cos - fy * targetH * sin)
  const ncy = fpy - (fx * targetW * sin + fy * targetH * cos)

  const newX = ncx - targetW / 2
  const newY = ncy - targetH / 2

  if (el.type === 'text') {
    const isCorner = !isSideHandle
    const startFontSize = startEl.fontSize || 16

    let finalW = targetW
    let finalFontSize = (el as TextElement).fontSize
    let finalH = isCorner ? targetW / ratio : startEl.height

    if (isCorner) {
      finalFontSize = Math.round(startFontSize * (targetW / startEl.width))
      finalW = (finalFontSize / startFontSize) * startEl.width
      finalH = finalW / ratio
    } else {
      finalW = targetW + 0.5
    }

    const ncx = fpx - (fx * finalW * cos - fy * finalH * sin)
    const ncy = fpy - (fx * finalW * sin + fy * finalH * cos)

    return {
      updates: {
        x: ncx - finalW / 2,
        y: ncy - finalH / 2,
        width: finalW,
        fontSize: finalFontSize,
        height: isCorner ? finalH : undefined,
      },
      isSnappedToOriginal,
    }
  }

  return {
    updates: {
      x: newX,
      y: newY,
      width: targetW,
      height: targetH,
    },
    isSnappedToOriginal,
  }
}
