import sharp from "sharp"

// Character to vestaboard code mapping
const charToCode: Record<string, number> = {
  " ": 0,
  A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7, H: 8, I: 9,
  J: 10, K: 11, L: 12, M: 13, N: 14, O: 15, P: 16, Q: 17,
  R: 18, S: 19, T: 20, U: 21, V: 22, W: 23, X: 24, Y: 25, Z: 26,
  "1": 27, "2": 28, "3": 29, "4": 30, "5": 31, "6": 32, "7": 33, "8": 34, "9": 35, "0": 36,
  "!": 37, "@": 38, "#": 39, "$": 40, "(": 41, ")": 42, "-": 44, "+": 46,
  "&": 47, "=": 48, ";": 49, ":": 50, "'": 52, '"': 53, "%": 54, ",": 55,
  ".": 56, "/": 59, "?": 60, "°": 62,
  "🟥": 63, "🟧": 64, "🟨": 65, "🟩": 66, "🟦": 67, "🟪": 68, "⬜": 69, "⬛": 70,
}

// Code to display info for rendering
const codeToDisplay: Record<number, { bg: string; fg: string; char?: string }> = {
  0: { bg: "#1a1a1a", fg: "#ffffff" }, // space (empty black tile)
  63: { bg: "#e63946", fg: "#ffffff" }, // red
  64: { bg: "#f4a261", fg: "#1a1a1a" }, // orange
  65: { bg: "#e9c46a", fg: "#1a1a1a" }, // yellow
  66: { bg: "#2a9d8f", fg: "#ffffff" }, // green
  67: { bg: "#0077b6", fg: "#ffffff" }, // blue
  68: { bg: "#9b5de5", fg: "#ffffff" }, // purple
  69: { bg: "#ffffff", fg: "#1a1a1a" }, // white
  70: { bg: "#1a1a1a", fg: "#ffffff" }, // black
}

// Code to character (for letters/numbers/symbols)
const codeToChar: Record<number, string> = {}
for (const [char, code] of Object.entries(charToCode)) {
  if (code >= 1 && code <= 62) {
    codeToChar[code] = char
  }
}

const TILE_SIZE = 24
const GAP = 2
const COLS = 22
const ROWS = 6

// Parse emoji grid string to number array
export const parseEmojiGrid = (grid: string): number[][] => {
  const lines = grid.trim().split("\n")
  const result: number[][] = []

  for (const line of lines) {
    const row: number[] = []
    const chars = [...line] // Handle multi-byte emoji correctly

    for (const char of chars) {
      const code = charToCode[char.toUpperCase()]
      if (code !== undefined) {
        row.push(code)
      }
    }

    // Pad or trim to 22 columns
    while (row.length < COLS) row.push(0)
    if (row.length > COLS) row.length = COLS

    result.push(row)
  }

  // Pad or trim to 6 rows
  while (result.length < ROWS) result.push(Array(COLS).fill(0))
  if (result.length > ROWS) result.length = ROWS

  return result
}

// Convert number grid to emoji string
export const gridToEmoji = (grid: number[][]): string => {
  const emojiMap: Record<number, string> = {
    0: " ",
    63: "🟥", 64: "🟧", 65: "🟨", 66: "🟩", 67: "🟦", 68: "🟪", 69: "⬜", 70: "⬛",
  }

  return grid
    .map((row) =>
      row
        .map((code) => {
          if (emojiMap[code] !== undefined) return emojiMap[code]
          if (codeToChar[code]) return codeToChar[code]
          return " "
        })
        .join("")
    )
    .join("\n")
}

// Render grid to SVG string
const gridToSvg = (grid: number[][]): string => {
  const width = COLS * TILE_SIZE + (COLS - 1) * GAP
  const height = ROWS * TILE_SIZE + (ROWS - 1) * GAP

  let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">`
  svg += `<rect width="${width}" height="${height}" fill="#0d0d0d"/>` // background

  for (let row = 0; row < ROWS; row++) {
    for (let col = 0; col < COLS; col++) {
      const code = grid[row]![col]!
      const x = col * (TILE_SIZE + GAP)
      const y = row * (TILE_SIZE + GAP)

      // Determine tile appearance
      let bg = "#1a1a1a"
      let fg = "#ffffff"
      let char: string | undefined

      const display = codeToDisplay[code]
      if (display) {
        bg = display.bg
        fg = display.fg
      } else if (codeToChar[code]) {
        char = codeToChar[code]
        bg = "#1a1a1a"
        fg = "#ffffff"
      }

      // Draw tile
      svg += `<rect x="${x}" y="${y}" width="${TILE_SIZE}" height="${TILE_SIZE}" rx="2" fill="${bg}"/>`

      // Draw character if present
      if (char) {
        const fontSize = 14
        const textX = x + TILE_SIZE / 2
        const textY = y + TILE_SIZE / 2 + fontSize * 0.35
        // Escape XML special characters
        const escaped = char.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
        svg += `<text x="${textX}" y="${textY}" font-family="Arial, sans-serif" font-size="${fontSize}" font-weight="bold" fill="${fg}" text-anchor="middle">${escaped}</text>`
      }
    }
  }

  svg += "</svg>"
  return svg
}

// Render emoji grid string to PNG buffer
export const renderToPng = async (emojiGrid: string): Promise<Buffer> => {
  const grid = parseEmojiGrid(emojiGrid)
  const svg = gridToSvg(grid)
  return sharp(Buffer.from(svg)).png().toBuffer()
}

// Render number grid to PNG buffer
export const renderGridToPng = async (grid: number[][]): Promise<Buffer> => {
  const svg = gridToSvg(grid)
  return sharp(Buffer.from(svg)).png().toBuffer()
}
