///|
pub struct ReleaseReadinessReport {
  target : String
  example : String
  budget_profile : String
  status : String
  checklist_count : Int
  passed_count : Int
  diagnostic_count : Int
  diagnostics : Array[String]
  summary : String
} derive(Debug, Eq)

///|
pub fn release_readiness_report(
  target~ : String,
  example~ : String,
  budget_profile~ : String,
  project : @wechat.WechatProject,
  profile : BuildProfile,
  profile_gate : BuildProfileGate,
  inspection : ProjectInspection,
  inspection_gate : ProjectInspectionGate,
) -> ReleaseReadinessReport {
  let diagnostics : Array[String] = []
  collect_release_diagnostics(
    diagnostics, project, profile, profile_gate, inspection, inspection_gate,
  )
  let checklist_count = 8
  let passed_count = release_passed_count(checklist_count, diagnostics.length())
  let status = if diagnostics.length() == 0 { "ready" } else { "blocked" }
  {
    target,
    example,
    budget_profile,
    status,
    checklist_count,
    passed_count,
    diagnostic_count: diagnostics.length(),
    diagnostics,
    summary: "Bunnia release readiness: target=\{target} example=\{example} budget=\{budget_profile} status=\{status} checks=\{passed_count}/\{checklist_count} diagnostics=\{diagnostics.length()}",
  }
}

///|
pub fn miniapp_release_readiness_report(
  target~ : String,
  example~ : String,
  budget_profile~ : String,
  project : @miniapp.MiniappProject,
  inspection : MiniappInspection,
  inspection_gate : MiniappInspectionGate,
) -> ReleaseReadinessReport {
  let diagnostics : Array[String] = []
  collect_miniapp_release_diagnostics(
    diagnostics, target, project, inspection, inspection_gate,
  )
  let checklist_count = 7
  let passed_count = release_passed_count(checklist_count, diagnostics.length())
  let status = if diagnostics.length() == 0 { "ready" } else { "blocked" }
  {
    target,
    example,
    budget_profile,
    status,
    checklist_count,
    passed_count,
    diagnostic_count: diagnostics.length(),
    diagnostics,
    summary: "Bunnia generic miniapp release readiness: target=\{target} example=\{example} budget=\{budget_profile} status=\{status} checks=\{passed_count}/\{checklist_count} diagnostics=\{diagnostics.length()}",
  }
}

///|
fn release_passed_count(checklist_count : Int, diagnostic_count : Int) -> Int {
  let count = checklist_count - diagnostic_count
  if count < 0 {
    0
  } else {
    count
  }
}

///|
fn collect_miniapp_release_diagnostics(
  diagnostics : Array[String],
  target : String,
  project : @miniapp.MiniappProject,
  inspection : MiniappInspection,
  inspection_gate : MiniappInspectionGate,
) -> Unit {
  if project.manifest.platform_id != target {
    diagnostics.push(
      "release-miniapp-target-mismatch:\{project.manifest.platform_id}/\{target}",
    )
  }
  if project.manifest.page_count != project.pages.length() {
    diagnostics.push(
      "release-miniapp-manifest-page-count-mismatch:\{project.manifest.page_count}/\{project.pages.length()}",
    )
  }
  if project.manifest.file_count + 1 != project.files.length() {
    diagnostics.push(
      "release-miniapp-manifest-file-count-mismatch:\{project.manifest.file_count + 1}/\{project.files.length()}",
    )
  }
  if !miniapp_project_has_file(project, "bunnia.manifest.json") {
    diagnostics.push("release-miniapp-manifest-missing:bunnia.manifest.json")
  }
  if !miniapp_project_has_file(project, "app.json") {
    diagnostics.push("release-miniapp-app-config-missing:app.json")
  }
  if miniapp_project_contains_secret_marker(project) {
    diagnostics.push("release-miniapp-frontend-secret-marker-found")
  }
  if miniapp_project_contains_literal_app_id(project) {
    diagnostics.push("release-miniapp-frontend-app-id-found")
  }
  if project.manifest.diagnostic_count > 0 {
    diagnostics.push(
      "release-miniapp-route-diagnostics:\{project.manifest.diagnostic_count}",
    )
  }
  if inspection.diagnostic_count > 0 {
    diagnostics.push(
      "release-miniapp-inspection-diagnostics:\{inspection.diagnostic_count}",
    )
  }
  if inspection_gate.diagnostics.length() > 0 {
    diagnostics.push(
      "release-miniapp-inspection-gate-diagnostics:\{inspection_gate.diagnostics.length()}",
    )
  }
}

///|
fn collect_release_diagnostics(
  diagnostics : Array[String],
  project : @wechat.WechatProject,
  profile : BuildProfile,
  profile_gate : BuildProfileGate,
  inspection : ProjectInspection,
  inspection_gate : ProjectInspectionGate,
) -> Unit {
  if project.manifest.page_count != project.page_count {
    diagnostics.push(
      "release-manifest-page-count-mismatch:\{project.manifest.page_count}/\{project.page_count}",
    )
  }
  if project.manifest.app_file_count + 1 != project.files.length() {
    diagnostics.push(
      "release-manifest-file-count-mismatch:\{project.manifest.app_file_count + 1}/\{project.files.length()}",
    )
  }
  if !project_has_file(project, "bunnia.manifest.json") {
    diagnostics.push("release-manifest-missing:bunnia.manifest.json")
  }
  if project_contains_secret_marker(project) {
    diagnostics.push("release-frontend-secret-marker-found")
  }
  if project_contains_literal_app_id(project) {
    diagnostics.push("release-frontend-app-id-found")
  }
  if profile.scene_insecure_remote_asset_count > 0 {
    diagnostics.push(
      "release-insecure-remote-scene-assets:\{profile.scene_insecure_remote_asset_count}",
    )
  }
  if profile.scene_unapproved_remote_asset_count > 0 {
    diagnostics.push(
      "release-unapproved-remote-scene-assets:\{profile.scene_unapproved_remote_asset_count}",
    )
  }
  if profile.backend_endpoint_count > 0 &&
    !project_has_file(project, "bunnia.backend.js") {
    diagnostics.push("release-backend-contract-without-adapter")
  }
  if profile.backend_endpoint_count > 0 &&
    !backend_adapter_has_audit_hooks(project) {
    diagnostics.push("release-backend-adapter-missing-audit-hooks")
  }
  if profile.route_diagnostic_count > 0 {
    diagnostics.push(
      "release-route-diagnostics:\{profile.route_diagnostic_count}",
    )
  }
  if profile.diagnostics.length() > 0 {
    diagnostics.push(
      "release-profile-diagnostics:\{profile.diagnostics.length()}",
    )
  }
  if profile_gate.diagnostics.length() > 0 {
    diagnostics.push(
      "release-profile-gate-diagnostics:\{profile_gate.diagnostics.length()}",
    )
  }
  if inspection.total_diagnostics > 0 {
    diagnostics.push(
      "release-inspection-diagnostics:\{inspection.total_diagnostics}",
    )
  }
  if inspection_gate.diagnostics.length() > 0 {
    diagnostics.push(
      "release-inspection-gate-diagnostics:\{inspection_gate.diagnostics.length()}",
    )
  }
}

///|
fn miniapp_project_has_file(
  project : @miniapp.MiniappProject,
  path : String,
) -> Bool {
  for file in project.files {
    if file.path == path {
      return true
    }
  }
  false
}

///|
fn project_has_file(project : @wechat.WechatProject, path : String) -> Bool {
  for file in project.files {
    if file.path == path {
      return true
    }
  }
  false
}

///|
fn project_file_content(
  project : @wechat.WechatProject,
  path : String,
) -> String {
  for file in project.files {
    if file.path == path {
      return file.content
    }
  }
  ""
}

///|
fn miniapp_project_contains_secret_marker(
  project : @miniapp.MiniappProject,
) -> Bool {
  for file in project.files {
    if generated_file_is_frontend(file.path) &&
      (
        file.content.contains("appSecret") ||
        file.content.contains("APP_SECRET") ||
        file.content.contains("secretKey") ||
        file.content.contains("privateKey")
      ) {
      return true
    }
  }
  false
}

///|
fn project_contains_secret_marker(project : @wechat.WechatProject) -> Bool {
  for file in project.files {
    if generated_file_is_frontend(file.path) &&
      (
        file.content.contains("appSecret") ||
        file.content.contains("APP_SECRET") ||
        file.content.contains("secretKey") ||
        file.content.contains("privateKey")
      ) {
      return true
    }
  }
  false
}

///|
fn miniapp_project_contains_literal_app_id(
  project : @miniapp.MiniappProject,
) -> Bool {
  for file in project.files {
    if file.path == "app.json" &&
      file.content.contains("\"appid\"") &&
      !file.content.contains("\"appid\": \"\"") &&
      !file.content.contains("\"appid\": \"touristappid\"") {
      return true
    }
  }
  false
}

///|
fn project_contains_literal_app_id(project : @wechat.WechatProject) -> Bool {
  for file in project.files {
    if file.path == "project.config.json" &&
      file.content.contains("\"appid\"") &&
      !file.content.contains("\"appid\": \"\"") &&
      !file.content.contains("\"appid\": \"touristappid\"") {
      return true
    }
  }
  false
}

///|
fn generated_file_is_frontend(path : String) -> Bool {
  path.has_suffix(".js") ||
  path.has_suffix(".json") ||
  path.has_suffix(".axml") ||
  path.has_suffix(".acss") ||
  path.has_suffix(".ttml") ||
  path.has_suffix(".ttss") ||
  path.has_suffix(".wxml") ||
  path.has_suffix(".wxss")
}

///|
fn backend_adapter_has_audit_hooks(project : @wechat.WechatProject) -> Bool {
  let content = project_file_content(project, "bunnia.backend.js")
  content.contains("replayKey") &&
  content.contains("bunniaSessionId") &&
  content.contains("x-miniapp-session") &&
  content.contains("backend.' + endpointId + '.request")
}