type SpriteProps = {
  src: string
  width: number
  height: number
  frames: number
  frameDuration: number
  columns?: number
  class?: string
  style?: string
  playing?: boolean
}

export const Sprite = (props: SpriteProps) => {
  const {
    src,
    width,
    height,
    frames,
    frameDuration,
    columns,
    class: className,
    style,
    playing = true,
  } = props

  const isGrid = columns !== undefined
  const rows = isGrid ? Math.ceil(frames / columns!) : 1
  const cols = isGrid ? columns! : frames

  const sheetWidth = cols * width
  const sheetHeight = rows * height
  const totalDuration = frames * frameDuration

  const keyframeId = `sprite-${Bun.hash(
    `${src}-${width}-${height}-${frames}-${frameDuration}-${columns}`
  ).toString(36)}`

  const keyframes = isGrid
    ? generateGridKeyframes(keyframeId, width, height, frames, columns!)
    : generateStripKeyframes(keyframeId, sheetWidth)

  const divStyle = [
    `width:${width}px`,
    `height:${height}px`,
    `background-image:url('${src}')`,
    `background-size:${sheetWidth}px ${sheetHeight}px`,
    `animation:${keyframeId} ${totalDuration}ms steps(${frames}) infinite`,
    playing ? "" : "animation-play-state:paused",
    style,
  ]
    .filter(Boolean)
    .join(";")

  return (
    <>
      <style>{keyframes}</style>
      <div class={className} style={divStyle} />
    </>
  )
}

const generateStripKeyframes = (id: string, sheetWidth: number): string =>
  `@keyframes ${id}{from{background-position:0 0}to{background-position:-${sheetWidth}px 0}}`

const generateGridKeyframes = (
  id: string,
  width: number,
  height: number,
  frames: number,
  columns: number
): string => {
  const steps: string[] = []
  for (let i = 0; i < frames; i++) {
    const col = i % columns
    const row = Math.floor(i / columns)
    const x = -col * width
    const y = -row * height
    const percent = (i / frames) * 100
    steps.push(`${percent}%{background-position:${x}px ${y}px}`)
  }
  return `@keyframes ${id}{${steps.join("")}}`
}
