import { readFileSync } from "node:fs"
import path from "node:path"
import { createHash } from "node:crypto"
import { loadBrand, type Brand } from "./config.ts"
import { parseSlots, type SlotSpec } from "./slot-parser.ts"
import { resolveSlotContent, renderSlotSvg, renderSlotBackground } from "./resolve.ts"

export type RenderArgs = {
  template: string
  title?: string
  subtitle?: string
  slots?: Record<string, string>
  out?: string
}

export type RenderResult = {
  path: string
  hash: string
  status: "rendered" | "skipped"
}

const SLOT_COMMENT_RE = /<!--\s*slot:[^>]*?-->\n?/g

export function buildSvg(
  templateSvg: string,
  brand: Brand,
  args: RenderArgs,
  drawImageDir: string,
): string {
  const slots = parseSlots(templateSvg)
  let svg = templateSvg
  const slotSvgs: string[] = []
  for (const slot of slots) {
    const value = args.slots?.[slot.name]
    if (value) {
      const bg = renderSlotBackground(slot, brand)
      if (bg) slotSvgs.push(bg)
      const resolved = resolveSlotContent(slot, brand, drawImageDir, value)
      if (resolved) slotSvgs.push(renderSlotSvg(slot, resolved))
    }
  }
  svg = svg.replace(SLOT_COMMENT_RE, "")
  svg = svg.replace(/\{\{base\}\}/g, brand.base)
  svg = svg.replace(/\{\{surface\}\}/g, brand.surface)
  svg = svg.replace(/\{\{fg\}\}/g, brand.fg)
  svg = svg.replace(/\{\{muted\}\}/g, brand.muted)
  svg = svg.replace(/\{\{accent\}\}/g, brand.accent)
  svg = svg.replace(/\{\{line\}\}/g, brand.line)
  svg = svg.replace(/\{\{title\}\}/g, escapeXml(args.title ?? ""))
  if (args.subtitle) {
    svg = svg.replace(/\{\{subtitle\}\}/g, escapeXml(args.subtitle))
  } else {
    svg = svg.replace(/[^\n]*\{\{subtitle\}\}[^\n]*\n?/g, "")
  }
  const insertPoint = svg.indexOf("</svg>")
  if (insertPoint === -1) return svg
  return svg.slice(0, insertPoint) + slotSvgs.join("\n") + "\n" + svg.slice(insertPoint)
}

export function computeHash(brand: Brand, templateSvg: string, args: RenderArgs): string {
  const data = JSON.stringify({
    brand,
    template: templateSvg,
    template_name: args.template,
    title: args.title ?? "",
    subtitle: args.subtitle ?? "",
    slots: args.slots ?? {},
    out: args.out ?? "",
  })
  return createHash("sha256").update(data).digest("hex")
}

export function loadTemplate(drawImageDir: string, name: string, templateDir?: string): string {
  const dir = templateDir ?? "templates"
  const base = path.isAbsolute(dir) ? dir : path.join(drawImageDir, dir)
  const templatePath = path.join(base, `${name}.svg`)
  return readFileSync(templatePath, "utf-8")
}

function escapeXml(s: string): string {
  return s
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&apos;")
}