///|
pub fn run_cli(request : CliRequest, input : String?) -> CliResult {
  match request.command {
    Help => success_cli(cli_help())
    Version => success_cli("moonbit-brandbook " + version())
    Demo => {
      let book = moonbit_brandbook()
      success_cli(render_cli_format(book, request.format))
    }
    Validate => {
      let source = match input {
        Some(text) if text != "" => text
        _ => request.input
      }
      if source == "" {
        failure_cli("validate requires --text or a native input adapter")
      } else {
        let parsed = parse_brand_document(source)
        match parsed.value {
          Some(book) => {
            let report = book.audit()
            if report.has_errors() {
              failure_cli(report_to_cli_text(report))
            } else {
              success_cli("valid: " + report.summary())
            }
          }
          None => failure_cli(diagnostics_to_text(parsed.diagnostics))
        }
      }
    }
    Render => {
      let source = match input {
        Some(text) if text != "" => text
        _ => request.input
      }
      if source == "" {
        failure_cli("render requires --text or a native input adapter")
      } else {
        let parsed = parse_brand_document(source)
        match parsed.value {
          Some(book) => success_cli(render_cli_format(book, request.format))
          None => failure_cli(diagnostics_to_text(parsed.diagnostics))
        }
      }
    }
    Benchmark => success_cli(run_benchmarks().to_markdown())
  }
}

///|
fn render_cli_format(book : BrandBook, format : CliFormat) -> String {
  match format {
    Markdown => book.to_markdown()
    Html => book.to_html()
    Css => book.to_css()
    Json => book.to_theme_json()
    Yaml => book.to_theme_yaml()
    Tailwind => book.to_tailwind_theme()
    Figma => book.to_figma_tokens()
  }
}

///|
fn report_to_cli_text(report : AuditReport) -> String {
  let lines : Array[String] = [report.summary()]
  for finding in report.findings {
    lines.push(
      finding.severity.label() + " " + finding.path + ": " + finding.message,
    )
  }
  lines.join("\n")
}

///|
fn diagnostics_to_text(diagnostics : DiagnosticBag) -> String {
  let lines : Array[String] = [diagnostics.summary()]
  for diagnostic in diagnostics.sorted().items {
    lines.push(
      diagnostic.severity.label() +
      " " +
      diagnostic.path +
      ": " +
      diagnostic.message,
    )
  }
  lines.join("\n")
}

///|
fn success_cli(output : String) -> CliResult {
  { output, errors: [], exit_code: 0 }
}

///|
fn failure_cli(message : String) -> CliResult {
  { output: message, errors: [message], exit_code: 1 }
}