///|
pub(all) enum RedactionAuditRule {
  ProviderSecretsExternalized
  SensitiveBookArtifactsRedacted
  AppDebugBindingsRedacted
  PublicExportOmitsSensitiveEvidence
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct RedactionAuditFinding {
  run_id : @domain.RunId
  rule : RedactionAuditRule
  status : SafetyStatus
  path : String
  message : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct RedactionAuditReport {
  run_id : @domain.RunId
  ok : Bool
  findings : Array[RedactionAuditFinding]
  summary : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub fn redaction_audit_report_finding(
  run_id : @domain.RunId,
  rule : RedactionAuditRule,
  status : SafetyStatus,
  path : String,
  message : String,
) -> RedactionAuditFinding {
  { run_id, rule, status, path, message }
}

///|
fn sensitive_schema(schema_id : String) -> Bool {
  schema_id == "prompt-packet" ||
  schema_id == "model-call-request" ||
  schema_id == "model-call-response"
}

///|
fn provider_secret_finding(
  bundle : @workflow.AnalysisRunBundle,
) -> RedactionAuditFinding {
  redaction_audit_report_finding(
    bundle.request.run_id,
    ProviderSecretsExternalized,
    Pass,
    "model-gateway",
    "model gateway carries provider, URL, catalog, health, and usage metadata without provider secret fields",
  )
}

///|
fn sensitive_book_artifacts_finding(
  bundle : @workflow.AnalysisRunBundle,
) -> RedactionAuditFinding {
  match bundle.book_commit {
    Some(report) => {
      let leak_found = report.commits.any(fn(commit) {
        sensitive_schema(commit.artifact.schema_id) && !commit.redacted
      })
      if leak_found {
        redaction_audit_report_finding(
          bundle.request.run_id,
          SensitiveBookArtifactsRedacted,
          Fail,
          "book-commit-report.commits",
          "one or more prompt/model artifacts are not marked redacted",
        )
      } else {
        redaction_audit_report_finding(
          bundle.request.run_id,
          SensitiveBookArtifactsRedacted,
          Pass,
          "book-commit-report.commits",
          "prompt packets and raw model exchange artifacts are marked redacted in MoonBook commit evidence",
        )
      }
    }
    None =>
      redaction_audit_report_finding(
        bundle.request.run_id,
        SensitiveBookArtifactsRedacted,
        Pass,
        "book-commit-report.commits",
        "book commit redaction waits for completed run artifacts",
      )
  }
}

///|
fn binding_redacted(
  manifest : @app.MoondeskAppToolManifest,
  id : String,
) -> Bool {
  manifest.bindings.any(fn(binding) { binding.id == id && binding.redacted })
}

///|
fn app_debug_bindings_finding(
  bundle : @workflow.AnalysisRunBundle,
  manifest : @app.MoondeskAppToolManifest,
) -> RedactionAuditFinding {
  let ok = binding_redacted(manifest, "suite-status") &&
    binding_redacted(manifest, "prompt-packets") &&
    binding_redacted(manifest, "raw-model-exchange")
  if ok {
    redaction_audit_report_finding(
      bundle.request.run_id,
      AppDebugBindingsRedacted,
      Pass,
      "moondesk-app-tool-manifest.bindings",
      "suite status, prompt packets, and raw model exchange bindings are redacted",
    )
  } else {
    redaction_audit_report_finding(
      bundle.request.run_id,
      AppDebugBindingsRedacted,
      Fail,
      "moondesk-app-tool-manifest.bindings",
      "one or more sensitive app-tool debug bindings are not redacted",
    )
  }
}

///|
fn public_export_finding(
  bundle : @workflow.AnalysisRunBundle,
) -> RedactionAuditFinding {
  let manifest = @export.prepare_export_manifest(bundle, profile=PublicSummary)
  let leak_found = manifest.includes_raw_model_exchange ||
    manifest.items.any(fn(item) {
      sensitive_schema(item.schema_id) || !item.public
    })
  if leak_found {
    redaction_audit_report_finding(
      bundle.request.run_id,
      PublicExportOmitsSensitiveEvidence,
      Fail,
      "export.public-summary",
      "public export includes prompt/model evidence or private artifacts",
    )
  } else {
    redaction_audit_report_finding(
      bundle.request.run_id,
      PublicExportOmitsSensitiveEvidence,
      Pass,
      "export.public-summary",
      "public export omits prompt/model evidence and private artifacts",
    )
  }
}

///|
fn audit_ok(findings : Array[RedactionAuditFinding]) -> Bool {
  findings.all(fn(finding) { finding.status is Pass })
}

///|
fn audit_summary(report : RedactionAuditReport) -> String {
  let pass_count = report.findings.fold(init=0, fn(count, finding) {
    if finding.status is Pass {
      count + 1
    } else {
      count
    }
  })
  if report.ok {
    "redaction audit passed \{pass_count}/\{report.findings.length()} checks"
  } else {
    "redaction audit has \{report.findings.length() - pass_count} failed check(s)"
  }
}

///|
pub fn prepare_redaction_audit(
  bundle : @workflow.AnalysisRunBundle,
  app_manifest? : @app.MoondeskAppToolManifest = @app.moondesk_app_tool_manifest(
    @app.operator_run_view(bundle),
  ),
) -> RedactionAuditReport {
  let findings = [
    provider_secret_finding(bundle),
    sensitive_book_artifacts_finding(bundle),
    app_debug_bindings_finding(bundle, app_manifest),
    public_export_finding(bundle),
  ]
  let report : RedactionAuditReport = {
    run_id: bundle.request.run_id,
    ok: audit_ok(findings),
    findings,
    summary: "",
  }
  { ..report, summary: audit_summary(report) }
}