///|
/// Deterministic, reusable starter brand books for examples and integration tests.
pub struct BrandTemplate {
  name : String
  description : String
  tags : Array[String]
} derive(Debug, Eq)

///|
pub fn BrandTemplate::new(
  name : String,
  description : String,
  tags : Array[String],
) -> BrandTemplate {
  { name, description, tags }
}

///|
pub fn BrandTemplate::minimal() -> BrandBook {
  BrandBook::{
    name: "Minimal brand template",
    tagline: "A small, coherent token set for a new product.",
    voice: Voice::{
      tone: "direct and helpful",
      writing_principles: ["Use plain language", "Show the next action"],
    },
    assets: AssetSet::{
      primary_logo: Logo::{
        name: "Minimal mark",
        path: "assets/minimal-mark.svg",
        min_width_px: 64,
        clear_space: Pixels(16),
        background: LightOrDark,
      },
      alternate_logos: [],
      imagery_style: "Use product evidence and generous whitespace.",
    },
    palette: Palette::{
      colors: [
        ColorToken::hex("primary", "#3157D5", role="primary action"),
        ColorToken::hex("ink", "#172033", role="text"),
        ColorToken::hex("surface", "#F7F9FC", role="surface"),
      ],
      gradients: [],
    },
    typography: Typography::{
      families: [
        FontToken::{
          name: "system-ui",
          fallback: "-apple-system, BlinkMacSystemFont, sans-serif",
          usage: "interface and documentation",
        },
      ],
      scale: [
        TypeStep::{ name: "body", size_px: 16, line_height_px: 24 },
        TypeStep::{ name: "title", size_px: 28, line_height_px: 36 },
      ],
    },
    components: [
      ComponentSpec::{
        name: "Action",
        purpose: "Give the user one clear next step.",
        anatomy: ["label", "focus ring"],
        tokens: ["primary", "surface"],
        states: ["default", "focus"],
      },
    ],
    forbidden: [
      MisuseRule::{
        title: "Do not add untracked colors",
        reason: "Untracked colors fragment the system.",
        replacement: "Use the nearest documented token.",
      },
    ],
    metadata: Meta::{
      source: "Built-in template",
      maintainer: "MoonBit Brandbook",
      license: "Apache-2.0",
    },
  }
}

///|
pub fn BrandTemplate::dark_variant(book : BrandBook) -> BrandBook {
  let dark_palette = Palette::{
    colors: book.palette.colors.map(fn(color) {
      match color.name {
        "paper" => { ..color, value: "#111827", role: "dark surface" }
        "ink" => { ..color, value: "#F7F9FC", role: "dark text" }
        _ => color
      }
    }),
    gradients: book.palette.gradients,
  }
  {
    ..book,
    name: book.name + " Dark",
    tagline: book.tagline + " Optimized for dark surfaces.",
    palette: dark_palette,
  }
}

///|
pub fn BrandTemplate::light_variant(book : BrandBook) -> BrandBook {
  let light_palette = book.palette.light_variant(8)
  { ..book, name: book.name + " Light", palette: light_palette }
}

///|
pub fn BrandTemplate::with_palette(
  book : BrandBook,
  palette : Palette,
) -> BrandBook {
  { ..book, palette, }
}

///|
pub fn BrandTemplate::with_name(book : BrandBook, name : String) -> BrandBook {
  { ..book, name, }
}

///|
pub fn BrandTemplate::with_tagline(
  book : BrandBook,
  tagline : String,
) -> BrandBook {
  { ..book, tagline, }
}

///|
pub fn BrandTemplate::with_accent(
  book : BrandBook,
  name : String,
  value : String,
  role : String,
) -> BrandBook {
  let colors = book.palette.colors
  colors.push(ColorToken::hex(name, value, role~))
  { ..book, palette: Palette::{ ..book.palette, colors, } }
}

///|
pub fn BrandTemplate::template_names() -> Array[String] {
  ["minimal", "dark", "light"]
}

///|
pub fn BrandTemplate::describe() -> String {
  "Built-in templates: minimal, dark variant, and light variant."
}

///|
pub fn BrandTemplate::metadata() -> BrandTemplate {
  BrandTemplate::new(
    "Brandbook starter",
    "Deterministic templates for examples, tests, and new projects.",
    ["tokens", "documentation", "accessibility"],
  )
}

///|
pub fn BrandTemplate::to_markdown(self : BrandTemplate) -> String {
  "## " +
  self.name +
  "\n\n" +
  self.description +
  "\n\nTags: " +
  self.tags.join(", ")
}

///|
pub fn BrandTemplate::to_json(self : BrandTemplate) -> String {
  "{\"name\":\"" +
  json_escape(self.name) +
  "\",\"description\":\"" +
  json_escape(self.description) +
  "\",\"tags\":[" +
  self.tags.map(fn(tag) { "\"" + json_escape(tag) + "\"" }).join(",") +
  "]}"
}

///|
pub fn BrandTemplate::is_named(self : BrandTemplate, name : String) -> Bool {
  normalize_identifier(self.name) == normalize_identifier(name)
}

///|
pub fn BrandTemplate::tagged(self : BrandTemplate, tag : String) -> Bool {
  self.tags.any(fn(value) {
    normalize_identifier(value) == normalize_identifier(tag)
  })
}