import { useRef, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { motion, AnimatePresence } from 'motion/react'
import { useStore } from '../store'
import type { CellStatus } from '../types'
import InkOverlay from './InkOverlay'
import CellFlip from './CellFlip'

function getCellSize(gridSize: number): number {
  if (gridSize <= 5) return 64
  if (gridSize <= 7) return 54
  if (gridSize <= 9) return 46
  if (gridSize <= 13) return 40
  return 36
}

export default function Grid() {
  const { t } = useTranslation()
  const svgRef = useRef<SVGSVGElement>(null)
  const wrapperRef = useRef<HTMLDivElement>(null)
  const cellRefs = useRef<(HTMLButtonElement | null)[]>([])
  const typingRef = useRef<HTMLInputElement>(null)
  const puzzle = useStore((s) => s.puzzle)
  const entries = useStore((s) => s.entries)
  const cellStatus = useStore((s) => s.cellStatus)
  const selectedCell = useStore((s) => s.selectedCell)
  const direction = useStore((s) => s.direction)
  const activeClue = useStore((s) => s.activeClue)
  const wordSpans = useStore((s) => s.wordSpans)
  const selectCell = useStore((s) => s.selectCell)
  const pencilEntries = useStore((s) => s.pencilEntries)
  const mpPlayers = useStore((s) => s.mpPlayers)
  const inputMode = useStore((s) => s.inputMode)

  const width = puzzle?.width ?? 0
  const height = puzzle?.height ?? 0

  useEffect(() => {
    if (!selectedCell || !wrapperRef.current) return
    if (!wrapperRef.current.contains(document.activeElement)) return
    const idx = selectedCell.row * width + selectedCell.col
    cellRefs.current[idx]?.focus()
  }, [selectedCell, width])

  if (!puzzle) return null

  const CELL = getCellSize(Math.max(width, height))
  const NUM_SIZE = Math.round(CELL * 0.26)
  const LETTER_SIZE = Math.round(CELL * 0.52)

  const activeSpan = wordSpans.find(
    (s) => s.number === activeClue && s.direction === direction,
  )
  const activeCells = new Set(
    activeSpan?.cells.map(([r, c]) => `${r},${c}`) ?? [],
  )

  // on touch devices, move focus into the hidden typing field so the
  // on-screen keyboard appears, with the tapped cell announced as its label
  const buildCellLabel = (r: number, c: number): string => {
    const st = useStore.getState()
    if (!st.puzzle) return t('grid.cellEmpty')
    if (st.puzzle.cells[r][c] === 'black') return t('grid.blackCell')
    const num = st.puzzle.cell_numbers[`${r},${c}`]
    const letter = st.entries[r]?.[c] || ''
    const pencilLetter = !letter && st.pencilEntries[r]?.[c] ? st.pencilEntries[r][c] : ''
    const status: CellStatus = st.cellStatus[r]?.[c] || 'default'
    return t('grid.cellLabel', { row: r + 1, col: c + 1 }) +
      (num ? t('grid.cellNumber', { num }) : '') +
      (letter ? t('grid.cellLetter', { letter }) : t('grid.cellEmpty')) +
      (status === 'correct' ? t('grid.cellCorrect') : status === 'incorrect' ? t('grid.cellIncorrect') : status === 'revealed' ? t('grid.cellRevealed') : pencilLetter ? t('grid.cellPencil', { letter: pencilLetter }) : '')
  }

  const focusTypingField = (r: number, c: number) => {
    if (!window.matchMedia('(pointer: coarse)').matches) return
    const field = typingRef.current
    if (field) {
      field.setAttribute('aria-label', buildCellLabel(r, c))
      field.focus({ preventScroll: true })
    }
  }

  return (
    <div
      ref={wrapperRef}
      className={`grid-wrapper${inputMode === 'stylus' ? ' stylus-active' : ''}`}
      style={{ maxWidth: width * CELL, width: '100%' }}
      onContextMenu={inputMode === 'stylus' ? (e => e.preventDefault()) : undefined}
    >
      <svg
        ref={svgRef}
        viewBox={`0 0 ${width * CELL} ${height * CELL}`}
        style={{ width: '100%', maxWidth: width * CELL, display: 'block' }}
        aria-hidden="true"
      >
        <defs>
          <style>{`
            .cell-num { font-family: 'DM Sans', system-ui, sans-serif; }
            .cell-letter { font-family: 'JetBrains Mono', ui-monospace, monospace; }
          `}</style>
        </defs>
        {Array.from({ length: height }, (_, r) =>
          Array.from({ length: width }, (_, c) => {
            const isBlack = puzzle.cells[r][c] === 'black'
            const isSelected = selectedCell?.row === r && selectedCell?.col === c
            const isActive = activeCells.has(`${r},${c}`)
            const num = puzzle.cell_numbers[`${r},${c}`]
            const letter = entries[r]?.[c] || ''
            const pencilLetter = !letter && pencilEntries[r]?.[c] ? pencilEntries[r][c] : ''
            const status: CellStatus = cellStatus[r]?.[c] || 'default'

            const x = c * CELL
            const y = r * CELL

            let fill = 'var(--cell-white)'
            if (isBlack) fill = 'var(--cell-black)'
            else if (isSelected) fill = 'var(--cell-selected)'
            else if (isActive) fill = 'var(--cell-active)'

            let textColor = 'var(--text)'
            if (status === 'correct') textColor = 'var(--correct)'
            if (status === 'incorrect') textColor = 'var(--incorrect)'
            if (status === 'revealed') textColor = 'var(--revealed)'

            return (
              <g
                key={`${r},${c}`}
                id={`cell-${r}-${c}`}
                data-cell={`${r},${c}`}
                onClick={() => {
                  if (isBlack) return
                  selectCell(r, c)
                  focusTypingField(r, c)
                }}
                style={{ cursor: isBlack ? 'default' : 'pointer' }}
              >
                <rect
                  x={x} y={y}
                  width={CELL} height={CELL}
                  fill={fill}
                  stroke={isSelected ? 'var(--accent)' : 'var(--cell-border)'}
                  strokeWidth={isSelected ? 2 : 0.5}
                />
                {!isBlack && num && (
                  <text
                    className="cell-num"
                    x={x + 2.5} y={y + NUM_SIZE}
                    fontSize={NUM_SIZE}
                    fill="var(--text-tertiary)"
                    style={{ userSelect: 'none' }}
                  >
                    {num}
                  </text>
                )}
                {!isBlack && letter && (
                  <text
                    className="cell-letter"
                    x={x + CELL / 2}
                    y={y + CELL / 2 + LETTER_SIZE * 0.35}
                    fontSize={LETTER_SIZE}
                    textAnchor="middle"
                    fill={textColor}
                    fontWeight={500}
                    style={{ userSelect: 'none' }}
                  >
                    {letter}
                  </text>
                )}
                {!isBlack && pencilLetter && (
                  <text
                    className="cell-letter cell-pencil"
                    x={x + CELL / 2}
                    y={y + CELL / 2 + LETTER_SIZE * 0.28}
                    fontSize={LETTER_SIZE * 0.72}
                    textAnchor="middle"
                    fill="var(--text-tertiary)"
                    fontWeight={400}
                    fontStyle="italic"
                    opacity={0.7}
                    style={{ userSelect: 'none' }}
                  >
                    {pencilLetter}
                  </text>
                )}
                {status === 'correct' && (
                  <text x={x + CELL - NUM_SIZE} y={y + CELL - 3} fontSize={NUM_SIZE * 0.9}
                    fill="var(--correct)" aria-hidden="true" style={{ userSelect: 'none' }}>+</text>
                )}
                {status === 'incorrect' && (
                  <text x={x + CELL - NUM_SIZE} y={y + CELL - 3} fontSize={NUM_SIZE * 0.9}
                    fill="var(--incorrect)" aria-hidden="true" style={{ userSelect: 'none' }}>x</text>
                )}
                {status === 'revealed' && (
                  <text x={x + CELL - NUM_SIZE} y={y + CELL - 3} fontSize={NUM_SIZE * 0.9}
                    fill="var(--revealed)" aria-hidden="true" style={{ userSelect: 'none' }}>*</text>
                )}
              </g>
            )
          }),
        )}
        <AnimatePresence>
          {mpPlayers.filter(p => p.cursor).map(p => {
            const [r, c] = p.cursor!
            return (
              <motion.rect key={`cursor-${p.id}`}
                x={c * CELL} y={r * CELL}
                width={CELL} height={CELL}
                fill={p.color}
                aria-hidden="true"
                style={{ pointerEvents: 'none' }}
                initial={{ opacity: 0 }}
                animate={{ opacity: 0.2 }}
                exit={{ opacity: 0 }}
                transition={{ duration: 0.15 }}
              />
            )
          })}
        </AnimatePresence>
        <rect
          x={0} y={0}
          width={width * CELL} height={height * CELL}
          fill="none"
          stroke="var(--cell-black)"
          strokeWidth={1.5}
        />
      </svg>
      {/* screen reader layer: a real ARIA grid mirroring the visual one */}
      <div
        className="grid-sr-grid"
        role="grid"
        aria-label={t('grid.ariaLabel', { width, height })}
        aria-rowcount={height}
        aria-colcount={width}
        style={{ gridTemplateColumns: `repeat(${width}, 1fr)`, aspectRatio: `${width} / ${height}` }}
      >
        {Array.from({ length: height }, (_, r) => (
          <div key={`sr-row-${r}`} role="row" aria-rowindex={r + 1} className="grid-sr-row" style={{ display: 'contents' }}>
            {Array.from({ length: width }, (_, c) => {
              const isBlack = puzzle.cells[r][c] === 'black'
              const isSelected = selectedCell?.row === r && selectedCell?.col === c
              const label = buildCellLabel(r, c)
              return (
                <button
                  key={`sr-${r}-${c}`}
                  ref={el => { cellRefs.current[r * width + c] = el }}
                  type="button"
                  className="grid-sr-cell"
                  role="gridcell"
                  aria-rowindex={r + 1}
                  aria-colindex={c + 1}
                  tabIndex={isSelected ? 0 : -1}
                  aria-label={label}
                  onClick={() => !isBlack && selectCell(r, c)}
                />
              )
            })}
          </div>
        ))}
      </div>
      <input
        ref={typingRef}
        className="grid-type-input"
        type="text"
        autoCapitalize="characters"
        autoComplete="off"
        spellCheck={false}
        inputMode="text"
        onChange={e => {
          const value = e.target.value
          e.target.value = ''
          for (const ch of value.toLowerCase()) {
            if (ch >= 'a' && ch <= 'z') useStore.getState().typeLetter(ch)
            else if (ch === ' ') useStore.getState().toggleDirection()
          }
        }}
        onKeyDown={e => {
          if (e.key === 'Backspace' && !e.currentTarget.value) {
            e.preventDefault()
            useStore.getState().deleteLetter()
          }
        }}
      />
      <CellFlip svgRef={svgRef} />
      <InkOverlay svgRef={svgRef} />
    </div>
  )
}
