///|
/// A structured outline for generated brand guides and documentation consumers.
pub struct GuideSection {
  id : String
  title : String
  summary : String
  body : String
  order : Int
} derive(Debug, Eq)

///|
pub fn GuideSection::new(
  id : String,
  title : String,
  summary : String,
  body : String,
  order : Int,
) -> GuideSection {
  { id, title, summary, body, order }
}

///|
pub fn GuideSection::anchor(self : GuideSection) -> String {
  normalize_identifier(self.id)
}

///|
pub fn GuideSection::is_empty(self : GuideSection) -> Bool {
  self.body.trim().to_owned() == ""
}

///|
pub fn GuideSection::to_markdown(self : GuideSection) -> String {
  "## " + self.title + "\n\n" + self.summary + "\n\n" + self.body
}

///|
pub fn GuideSection::to_json(self : GuideSection) -> String {
  "{\"id\":\"" +
  json_escape(self.id) +
  "\",\"title\":\"" +
  json_escape(self.title) +
  "\",\"summary\":\"" +
  json_escape(self.summary) +
  "\",\"order\":" +
  self.order.to_string() +
  "}"
}

///|
pub struct GuideOutline {
  title : String
  sections : Array[GuideSection]
} derive(Debug, Eq)

///|
pub fn GuideOutline::for_brand_book(book : BrandBook) -> GuideOutline {
  {
    title: book.name,
    sections: [
      GuideSection::new(
        "metadata",
        "Positioning",
        book.tagline,
        book.render_metadata_panel(),
        10,
      ),
      GuideSection::new(
        "voice",
        "Voice",
        book.voice.tone,
        book.render_voice_section(),
        20,
      ),
      GuideSection::new(
        "logo",
        "Logo",
        book.assets.imagery_style,
        book.render_logo_section(),
        30,
      ),
      GuideSection::new(
        "color",
        "Color",
        "Semantic palette and gradients",
        book.render_color_section(),
        40,
      ),
      GuideSection::new(
        "type",
        "Typography",
        "Readable type scale",
        book.render_typography_section(),
        50,
      ),
      GuideSection::new(
        "components",
        "Components",
        "Reusable component contracts",
        book.render_component_section(),
        60,
      ),
      GuideSection::new(
        "misuse",
        "Misuse",
        "Guardrails for common mistakes",
        book.render_misuse_section(),
        70,
      ),
    ],
  }
}

///|
pub fn GuideOutline::empty(title : String) -> GuideOutline {
  { title, sections: [] }
}

///|
pub fn GuideOutline::add(
  self : GuideOutline,
  section : GuideSection,
) -> GuideOutline {
  let sections = self.sections
  sections.push(section)
  { ..self, sections, }
}

///|
pub fn GuideOutline::len(self : GuideOutline) -> Int {
  self.sections.length()
}

///|
pub fn GuideOutline::ids(self : GuideOutline) -> Array[String] {
  self.sections.map(fn(section) { section.id })
}

///|
pub fn GuideOutline::find(self : GuideOutline, id : String) -> GuideSection? {
  for section in self.sections {
    if normalize_identifier(section.id) == normalize_identifier(id) {
      return Some(section)
    }
  }
  None
}

///|
pub fn GuideOutline::non_empty(self : GuideOutline) -> Array[GuideSection] {
  self.sections.filter(fn(section) { !section.is_empty() })
}

///|
pub fn GuideOutline::to_markdown(self : GuideOutline) -> String {
  let lines : Array[String] = ["# " + self.title, ""]
  for section in self.sections {
    if !section.is_empty() {
      lines.push(section.to_markdown())
      lines.push("")
    }
  }
  lines.join("\n")
}

///|
pub fn GuideOutline::to_toc(self : GuideOutline) -> String {
  let lines : Array[String] = ["## Contents", ""]
  for section in self.sections {
    lines.push("- [" + section.title + "](#" + section.anchor() + ")")
  }
  lines.join("\n")
}

///|
pub fn GuideOutline::to_json(self : GuideOutline) -> String {
  "{\"title\":\"" +
  json_escape(self.title) +
  "\",\"sections\":[" +
  self.sections.map(fn(section) { section.to_json() }).join(",") +
  "]}"
}

///|
pub fn BrandBook::guide_outline(self : BrandBook) -> GuideOutline {
  GuideOutline::for_brand_book(self)
}

///|
pub fn BrandBook::guide_toc(self : BrandBook) -> String {
  self.guide_outline().to_toc()
}