///|
pub struct ExportEntry {
  name : String
  format : String
  extension : String
  output_bytes : Int
  description : String
} derive(Debug, Eq)

///|
pub struct ExportManifest {
  project : String
  version : String
  entries : Array[ExportEntry]
} derive(Debug, Eq)

///|
pub fn ExportEntry::new(
  name : String,
  format : String,
  extension : String,
  output_bytes : Int,
  description : String,
) -> ExportEntry {
  { name, format, extension, output_bytes, description }
}

///|
pub fn ExportManifest::empty(
  project : String,
  version : String,
) -> ExportManifest {
  { project, version, entries: [] }
}

///|
pub fn ExportManifest::add(
  self : ExportManifest,
  entry : ExportEntry,
) -> ExportManifest {
  let entries : Array[ExportEntry] = []
  for item in self.entries {
    entries.push(item)
  }
  entries.push(entry)
  { ..self, entries, }
}

///|
pub fn ExportManifest::for_brand_book(book : BrandBook) -> ExportManifest {
  let manifest = ExportManifest::empty(book.name, version())
  let mut result = manifest
  result = result.add(
    ExportEntry::new(
      "brand-guide",
      "Markdown",
      "md",
      book.to_markdown().length(),
      "human-readable brand guide",
    ),
  )
  result = result.add(
    ExportEntry::new(
      "brand-guide",
      "HTML",
      "html",
      book.to_html().length(),
      "static documentation page",
    ),
  )
  result = result.add(
    ExportEntry::new(
      "theme",
      "CSS",
      "css",
      book.to_css().length(),
      "custom properties and type scale",
    ),
  )
  result = result.add(
    ExportEntry::new(
      "theme",
      "JSON",
      "json",
      book.to_theme_json().length(),
      "flat theme token export",
    ),
  )
  result = result.add(
    ExportEntry::new(
      "theme",
      "YAML",
      "yaml",
      book.to_theme_yaml().length(),
      "reviewable theme token export",
    ),
  )
  result = result.add(
    ExportEntry::new(
      "theme",
      "Tailwind",
      "json",
      book.to_tailwind_theme().length(),
      "Tailwind theme extension",
    ),
  )
  result = result.add(
    ExportEntry::new(
      "theme",
      "Figma Tokens",
      "json",
      book.to_figma_tokens().length(),
      "Figma Tokens-style interchange",
    ),
  )
  result
}

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

///|
pub fn ExportManifest::total_bytes(self : ExportManifest) -> Int {
  let mut total = 0
  for entry in self.entries {
    total += entry.output_bytes
  }
  total
}

///|
pub fn ExportManifest::formats(self : ExportManifest) -> Array[String] {
  let result : Array[String] = []
  for entry in self.entries {
    if !result.any(fn(item) { item == entry.format }) {
      result.push(entry.format)
    }
  }
  result
}

///|
pub fn ExportManifest::to_markdown(self : ExportManifest) -> String {
  let lines : Array[String] = [
    "## Export manifest",
    "",
    "Project: `" + self.project + "`",
    "Version: `" + self.version + "`",
    "",
    "| Artifact | Format | Extension | Bytes | Description |",
    "| --- | --- | --- | ---: | --- |",
  ]
  for entry in self.entries {
    lines.push(
      "| " +
      entry.name +
      " | " +
      entry.format +
      " | `." +
      entry.extension +
      "` | " +
      entry.output_bytes.to_string() +
      " | " +
      entry.description +
      " |",
    )
  }
  lines.join("\n")
}

///|
pub fn ExportManifest::to_json(self : ExportManifest) -> String {
  let builder = StringBuilder::new()
  builder.write_string("{\n  \"project\": \"")
  builder.write_string(json_escape(self.project))
  builder.write_string("\",\n  \"version\": \"")
  builder.write_string(json_escape(self.version))
  builder.write_string("\",\n  \"entries\": [\n")
  for i, entry in self.entries {
    if i > 0 {
      builder.write_string(",\n")
    }
    builder.write_string("    {\"name\": \"")
    builder.write_string(json_escape(entry.name + "." + entry.extension))
    builder.write_string("\", \"format\": \"")
    builder.write_string(json_escape(entry.format))
    builder.write_string("\", \"extension\": \"")
    builder.write_string(json_escape(entry.extension))
    builder.write_string("\", \"bytes\": ")
    builder.write_string(entry.output_bytes.to_string())
    builder.write_string(", \"description\": \"")
    builder.write_string(json_escape(entry.description))
    builder.write_string("\"}")
  }
  builder.write_string("\n  ]\n}\n")
  builder.to_string()
}

///|
pub fn BrandBook::export_manifest_markdown(self : BrandBook) -> String {
  ExportManifest::for_brand_book(self).to_markdown()
}

///|
pub fn BrandBook::export_manifest_json(self : BrandBook) -> String {
  ExportManifest::for_brand_book(self).to_json()
}