///|
/// Release gates that combine validation, content, accessibility, and export checks.
pub struct ReleasePolicy {
  minimum_score : Int
  require_accessibility : Bool
  require_content : Bool
  require_non_empty_exports : Bool
  required_formats : Array[String]
} derive(Debug, Eq)

///|
pub fn ReleasePolicy::default() -> ReleasePolicy {
  {
    minimum_score: 70,
    require_accessibility: true,
    require_content: false,
    require_non_empty_exports: true,
    required_formats: ["markdown", "html", "json"],
  }
}

///|
pub fn ReleasePolicy::strict() -> ReleasePolicy {
  {
    minimum_score: 85,
    require_accessibility: true,
    require_content: true,
    require_non_empty_exports: true,
    required_formats: [
      "markdown", "html", "css", "json", "yaml", "tailwind", "figma",
    ],
  }
}

///|
pub fn ReleasePolicy::with_minimum_score(
  self : ReleasePolicy,
  score : Int,
) -> ReleasePolicy {
  {
    ..self,
    minimum_score: if score < 0 {
      0
    } else if score > 100 {
      100
    } else {
      score
    },
  }
}

///|
pub fn ReleasePolicy::with_content_requirement(
  self : ReleasePolicy,
  required : Bool,
) -> ReleasePolicy {
  { ..self, require_content: required }
}

///|
pub fn ReleasePolicy::with_formats(
  self : ReleasePolicy,
  formats : Array[String],
) -> ReleasePolicy {
  { ..self, required_formats: formats }
}

///|
pub struct ReleaseCheck {
  name : String
  passed : Bool
  message : String
} derive(Debug, Eq)

///|
pub fn ReleaseCheck::new(
  name : String,
  passed : Bool,
  message : String,
) -> ReleaseCheck {
  { name, passed, message }
}

///|
pub fn ReleaseCheck::status(self : ReleaseCheck) -> String {
  if self.passed {
    "pass"
  } else {
    "fail"
  }
}

///|
pub struct ReleaseReport {
  ready : Bool
  checks : Array[ReleaseCheck]
  score : Int
} derive(Debug, Eq)

///|
pub fn BrandBook::release_report(
  self : BrandBook,
  policy : ReleasePolicy,
) -> ReleaseReport {
  let quality = BrandQualityReport::from_brand_book(self)
  let manifest = ExportManifest::for_brand_book(self)
  let checks : Array[ReleaseCheck] = []
  checks.push(
    ReleaseCheck::new(
      "quality score",
      quality.score >= policy.minimum_score,
      quality.score.to_string() + "/100",
    ),
  )
  checks.push(
    ReleaseCheck::new(
      "validation",
      !quality.audit.has_errors(),
      quality.audit.summary(),
    ),
  )
  if policy.require_accessibility {
    checks.push(
      ReleaseCheck::new(
        "accessibility",
        self.accessibility_score() >= 70,
        self.accessibility_score().to_string() + "/100",
      ),
    )
  }
  if policy.require_content {
    let content = self.audit_content(ContentPolicy::strict())
    checks.push(
      ReleaseCheck::new("content", !content.has_errors(), content.summary()),
    )
  }
  if policy.require_non_empty_exports {
    checks.push(
      ReleaseCheck::new(
        "exports",
        manifest.total_bytes() > 0,
        manifest.total_bytes().to_string() + " bytes",
      ),
    )
  }
  for format in policy.required_formats {
    checks.push(
      ReleaseCheck::new(
        "format:" + format,
        manifest.formats().contains(format),
        "required format present",
      ),
    )
  }
  {
    ready: checks.all(fn(check) { check.passed }),
    checks,
    score: quality.score,
  }
}

///|
pub fn ReleaseReport::passed(self : ReleaseReport) -> Bool {
  self.ready
}

///|
pub fn ReleaseReport::failed_checks(
  self : ReleaseReport,
) -> Array[ReleaseCheck] {
  self.checks.filter(fn(check) { !check.passed })
}

///|
pub fn ReleaseReport::passed_checks(
  self : ReleaseReport,
) -> Array[ReleaseCheck] {
  self.checks.filter(fn(check) { check.passed })
}

///|
pub fn ReleaseReport::check_named(
  self : ReleaseReport,
  name : String,
) -> ReleaseCheck? {
  for check in self.checks {
    if check.name == name {
      return Some(check)
    }
  }
  None
}

///|
pub fn ReleaseReport::summary(self : ReleaseReport) -> String {
  self.score.to_string() +
  "/100, " +
  self.passed_checks().length().to_string() +
  "/" +
  self.checks.length().to_string() +
  " checks passed"
}

///|
pub fn ReleaseReport::to_markdown(self : ReleaseReport) -> String {
  let status = if self.ready { "ready" } else { "blocked" }
  let lines : Array[String] = [
    "# Release readiness",
    "",
    "Status: **" + status + "**",
    "",
    "| Check | Status | Evidence |",
    "| --- | --- | --- |",
  ]
  for check in self.checks {
    lines.push(
      "| " + check.name + " | " + check.status() + " | " + check.message + " |",
    )
  }
  lines.join("\n")
}

///|
pub fn ReleaseReport::to_json(self : ReleaseReport) -> String {
  "{\"ready\":" +
  self.ready.to_string() +
  ",\"score\":" +
  self.score.to_string() +
  ",\"checks\":[" +
  self.checks
  .map(fn(check) {
    "{\"name\":\"" +
    json_escape(check.name) +
    "\",\"passed\":" +
    check.passed.to_string() +
    ",\"message\":\"" +
    json_escape(check.message) +
    "\"}"
  })
  .join(",") +
  "]}"
}

///|
pub fn BrandBook::is_release_ready(self : BrandBook) -> Bool {
  self.release_report(ReleasePolicy::default()).passed()
}

///|
pub fn BrandBook::release_markdown(self : BrandBook) -> String {
  self.release_report(ReleasePolicy::default()).to_markdown()
}