#!/usr/bin/env node
// Parses src/lib/accentVariants.ts and emits a Swift mirror under
// targets/watch/Generated/AccentVariants.swift. The 8-variant catalogue
// is canonical on the JS side (it's the source for tamagui.config.ts's
// 16 light_accent* / dark_accent* sub-themes), so the watch reads from
// the same source via this build-time mirror — keeps a per-account
// accent flip on the phone in lock-step with the watch's tint without
// a hand-edit-two-places ritual.

import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'

const HERE = dirname(fileURLToPath(import.meta.url))
const REPO_ROOT = join(HERE, '..', '..')
const SRC_TS = join(REPO_ROOT, 'src', 'lib', 'accentVariants.ts')
const OUT = join(REPO_ROOT, 'targets', 'watch', 'Generated', 'AccentVariants.swift')

function parseVariants(src) {
  // Match the whole `ACCENT_VARIANTS = { ... }` literal — variants are
  // hand-authored as `1: { name: '…', light: '#…', lightPressed: …, dark:
  // '#…', darkPressed: …, onAccent: '#…', onAccentDark: '#…' }` — we
  // only need name/light/dark for the watch.
  const blockMatch = src.match(/ACCENT_VARIANTS[^=]*=\s*\{([\s\S]*?)\n\}\s*\n/)
  if (!blockMatch) {
    throw new Error('gen-accent-variants: ACCENT_VARIANTS object literal not found')
  }
  const body = blockMatch[1]
  const variants = []
  // Each entry starts with a numeric key followed by a brace block.
  const entryRe = /(\d+):\s*\{([\s\S]*?)\}\s*,?/g
  let m
  while ((m = entryRe.exec(body)) !== null) {
    const id = Number(m[1])
    const inner = m[2]
    const name = (inner.match(/name:\s*'([^']+)'/) || [])[1]
    const light = (inner.match(/light:\s*'#([0-9A-Fa-f]{6})'/) || [])[1]
    const dark = (inner.match(/\bdark:\s*'#([0-9A-Fa-f]{6})'/) || [])[1]
    if (!name || !light || !dark) {
      throw new Error(
        `gen-accent-variants: variant ${id} missing name/light/dark — got name=${name} light=${light} dark=${dark}`
      )
    }
    variants.push({ id, name, light, dark })
  }
  if (variants.length !== 8) {
    throw new Error(
      `gen-accent-variants: expected 8 variants, parsed ${variants.length}. Update this script if the catalogue genuinely changed.`
    )
  }
  return variants
}

function escapeSwift(s) {
  return String(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
}

export function generate() {
  const src = readFileSync(SRC_TS, 'utf8')
  const variants = parseVariants(src)
  const lines = variants
    .map(
      (v) =>
        `        ${v.id}: Spec(name: "${escapeSwift(v.name)}", light: 0x${v.light.toUpperCase()}, dark: 0x${v.dark.toUpperCase()})`
    )
    .join(',\n')
  const swift = `// AUTO-GENERATED — do not edit. Source: src/lib/accentVariants.ts
// Regenerate via \`node targets/_scripts/gen-accent-variants.mjs\` (runs at
// prebuild time via plugins/withWatchGenerated.js).
//
// Mirror of the 8-variant catalogue used by tamagui.config.ts to
// generate the light_accent* / dark_accent* sub-themes. The watch is
// always in dark scheme (no light system colour scheme on watchOS), so
// the \`tint(for:)\` accessor returns the dark hex.

import SwiftUI

enum AccentVariants {
    struct Spec {
        let name: String
        let light: UInt32
        let dark: UInt32
    }

    static let table: [Int: Spec] = [
${lines}
    ]

    /// Returns the dark-scheme tint for a given variant id (1..8). Falls
    /// back to variant 1 (Electric Blue) for unknown ids — matches the
    /// phone's positional default in AccountStore.upsert.
    static func tint(for id: Int) -> Color {
        let spec = table[id] ?? table[1]!
        return Color(hex: spec.dark)
    }
}

extension Color {
    /// 24-bit RRGGBB initializer. The watch's accent colours are
    /// authored as hex literals on the TS side; mirroring them as
    /// UInt32 keeps the wire format compact and lets us avoid pulling
    /// in a string-parsing helper for what is fundamentally a literal.
    init(hex rgb: UInt32) {
        let r = Double((rgb >> 16) & 0xFF) / 255.0
        let g = Double((rgb >> 8) & 0xFF) / 255.0
        let b = Double(rgb & 0xFF) / 255.0
        self.init(.sRGB, red: r, green: g, blue: b, opacity: 1.0)
    }
}
`
  mkdirSync(dirname(OUT), { recursive: true })
  writeFileSync(OUT, swift)
  return { path: OUT, count: variants.length }
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const { path, count } = generate()
  console.log(`gen-accent-variants: wrote ${path} (${count} variants)`)
}
