import { useEffect, useRef, useState } from 'react'
import { useStore } from '../store'

interface FlipItem {
  row: number
  col: number
  oldLetter: string
  newLetter: string
  clueNumber: number | undefined
  id: number
}

let flipId = 0

export default function CellFlip({ svgRef }: { svgRef: React.RefObject<SVGSVGElement | null> }) {
  const entries = useStore((s) => s.entries)
  const puzzle = useStore((s) => s.puzzle)
  const [flips, setFlips] = useState<FlipItem[]>([])
  const prevEntries = useRef<string[][]>([])
  const timeouts = useRef<ReturnType<typeof setTimeout>[]>([])

  useEffect(() => () => { timeouts.current.forEach(id => clearTimeout(id)) }, [])

  useEffect(() => {
    if (!puzzle) return

    const prev = prevEntries.current
    const curr = entries
    const newFlips: FlipItem[] = []

    for (let r = 0; r < curr.length; r++) {
      for (let c = 0; c < (curr[r]?.length || 0); c++) {
        const was = prev[r]?.[c] || ''
        const now = curr[r]?.[c] || ''
        if (now && now !== was) {
          const num = puzzle.cell_numbers[`${r},${c}`]
          newFlips.push({ row: r, col: c, oldLetter: was, newLetter: now, clueNumber: num, id: ++flipId })
        }
      }
    }

    prevEntries.current = curr.map(r => [...r])

    // skip animation when bulk-loading (e.g. reopening a solved puzzle)
    const totalWhiteCells = puzzle.cells.flat().filter(c => c !== 'black').length
    if (newFlips.length > 0 && newFlips.length < totalWhiteCells * 0.5) {
      // hide the SVG letter text for the flipping cells
      if (svgRef.current) {
        for (const flip of newFlips) {
          const texts = svgRef.current.querySelectorAll<SVGElement>(`g[data-cell="${flip.row},${flip.col}"] .cell-letter`)
          texts.forEach(t => { t.style.opacity = '0' })
        }
      }

      setFlips(f => [...f, ...newFlips])
      timeouts.current.push(setTimeout(() => {
        // restore SVG letter visibility
        if (svgRef.current) {
          for (const flip of newFlips) {
            const texts = svgRef.current.querySelectorAll<SVGElement>(`g[data-cell="${flip.row},${flip.col}"] .cell-letter`)
            texts.forEach(t => { t.style.opacity = '1' })
          }
        }
        setFlips(f => f.filter(fl => !newFlips.some(n => n.id === fl.id)))
      }, 600))
    }
  }, [entries, puzzle, svgRef])

  if (!puzzle || !svgRef.current || flips.length === 0) return null

  const svg = svgRef.current
  const rect = svg.getBoundingClientRect()
  const cellW = rect.width / puzzle.width
  const cellH = rect.height / puzzle.height
  const fontSize = Math.round(cellW * 0.52)
  const numSize = Math.round(cellW * 0.26)

  return (
    <>
      {flips.map(flip => (
        <div
          key={flip.id}
          className="flip-scene"
          style={{
            position: 'absolute',
            left: flip.col * cellW,
            top: flip.row * cellH,
            width: cellW,
            height: cellH,
          }}
        >
          <div className="flip-backing" />
          <div className="flip-card flip-card-animate">
            <div className="flip-face flip-front">
              {flip.clueNumber && (
                <span className="flip-num" style={{ fontSize: numSize }}>{flip.clueNumber}</span>
              )}
              {flip.oldLetter && <span className="flip-letter" style={{ fontSize }} aria-hidden="true">{flip.oldLetter}</span>}
            </div>
            <div className="flip-face flip-back">
              {flip.clueNumber && (
                <span className="flip-num" style={{ fontSize: numSize }}>{flip.clueNumber}</span>
              )}
              <span className="flip-letter" style={{ fontSize }} aria-hidden="true">{flip.newLetter}</span>
            </div>
          </div>
        </div>
      ))}
    </>
  )
}
