///|
pub(all) enum TokenKind {
  Color
  FontSize
  Spacing
  Radius
  Shadow
} derive(Debug, Eq)

///|
pub(all) struct Token {
  name : String
  kind : TokenKind
  value : String
  description : String
} derive(Debug, Eq)

///|
pub fn Token::color(
  name : String,
  value : String,
  description~ : String,
) -> Token {
  { name, kind: Color, value, description }
}

///|
pub fn Token::font_size(
  name : String,
  value : String,
  description~ : String,
) -> Token {
  { name, kind: FontSize, value, description }
}

///|
pub fn Token::spacing(
  name : String,
  value : String,
  description~ : String,
) -> Token {
  { name, kind: Spacing, value, description }
}

///|
pub fn Token::radius(
  name : String,
  value : String,
  description~ : String,
) -> Token {
  { name, kind: Radius, value, description }
}

///|
pub fn Token::shadow(
  name : String,
  value : String,
  description~ : String,
) -> Token {
  { name, kind: Shadow, value, description }
}

///|
pub fn TokenKind::label(self : TokenKind) -> String {
  match self {
    Color => "color"
    FontSize => "font-size"
    Spacing => "spacing"
    Radius => "radius"
    Shadow => "shadow"
  }
}

///|
pub fn Token::css_variable(self : Token) -> String {
  "\{self.css_name()}: \{self.value};"
}

///|
pub fn Token::json_object(self : Token) -> String {
  "{ \"name\": \"\{json_string(self.name)}\", \"kind\": \"\{json_string(self.kind.label())}\", \"value\": \"\{json_string(self.value)}\", \"description\": \"\{json_string(self.description)}\" }"
}

///|
fn json_string(value : String) -> String {
  value.escape(quote=false)
}

///|
pub fn Token::moonbit_const(self : Token) -> String {
  "pub let \{self.name.to_identifier()} : String = \"\{self.value.escape(quote=false)}\""
}

///|
pub fn Token::markdown_row(self : Token) -> String {
  "| `\{markdown_escape(self.name)}` | \{self.kind.label()} | `\{markdown_escape(self.value)}` | \{markdown_escape(self.description)} |"
}

///|
fn markdown_escape(value : String) -> String {
  value
  .replace(old="|", new="\\|")
  .replace(old="\n", new=" ")
  .replace(old="\r", new=" ")
}

///|
pub fn to_css(tokens : Array[Token]) -> String {
  let rows = [ for token in tokens => "  \{token.css_variable()}" ]
  ":root {\n\{rows.join("\n")}\n}\n"
}

///|
pub fn to_json(tokens : Array[Token]) -> String {
  let rows = [ for token in tokens => "  \{token.json_object()}" ]
  "[\n\{rows.join(",\n")}\n]\n"
}

///|
pub fn to_moonbit_constants(tokens : Array[Token]) -> String {
  let rows = [ for token in tokens => token.moonbit_const() ]
  "\{rows.join("\n")}\n"
}

///|
pub fn to_markdown_table(tokens : Array[Token]) -> String {
  let header = "| Name | Kind | Value | Description |\n| --- | --- | --- | --- |"
  let rows = [ for token in tokens => token.markdown_row() ]
  "\{header}\n\{rows.join("\n")}\n"
}

///|
pub fn sample_tokens() -> Array[Token] {
  [
    Token::color("brand-primary", "#4f46e5", description="Primary action color"),
    Token::color("brand-success", "#16a34a", description="Positive state color"),
    Token::font_size("font-body", "16px", description="Default body text"),
    Token::font_size("font-title", "28px", description="Section title text"),
    Token::spacing("space-2", "8px", description="Compact gap"),
    Token::spacing("space-4", "16px", description="Default gap"),
    Token::radius("radius-card", "8px", description="Standard card corner"),
    Token::shadow(
      "shadow-panel",
      "0 8px 24px rgba(15, 23, 42, 0.12)",
      description="Raised panel shadow",
    ),
  ]
}

///|
fn String::to_identifier(self : String) -> String {
  let chars = [
    for c in self => if c == '-' || c == '/' || c == '.' { "_" } else { "\{c}" }
  ]
  chars.join("")
}