///|
pub(all) enum SafetyCheckKind {
  NoBrokerExecutionPath
  DecisionPolicyBoundary
  ContextBudgetWithinWindow
  BookCommitCompleteness
  SecretRedactionBoundary
  PublicExportRedaction
  ReplayWithoutLiveMarket
  SuiteOwnershipBoundary
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) enum SafetyStatus {
  Pass
  Fail
} derive(Debug, Eq, ToJson, FromJson)

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

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

///|
pub fn safety_finding(
  run_id : @domain.RunId,
  kind : SafetyCheckKind,
  status : SafetyStatus,
  path : String,
  message : String,
) -> SafetyFinding {
  { run_id, kind, status, path, message }
}

///|
fn disallowed_tool_name(name : String) -> Bool {
  name == "execute_order" ||
  name == "place_order" ||
  name == "submit_order" ||
  name == "broker_order"
}

///|
fn no_broker_execution_finding(
  run_id : @domain.RunId,
  manifest : @pack.PackManifest,
) -> SafetyFinding {
  let blocked = manifest.tools.any(fn(tool) { disallowed_tool_name(tool.name) })
  if blocked {
    safety_finding(
      run_id,
      NoBrokerExecutionPath,
      Fail,
      "pack.tools",
      "pack declares a broker/order execution tool",
    )
  } else {
    safety_finding(
      run_id,
      NoBrokerExecutionPath,
      Pass,
      "pack.tools",
      "pack exposes analysis, review, replay, export, and view tools only",
    )
  }
}

///|
fn decision_policy_finding(
  bundle : @workflow.AnalysisRunBundle,
) -> SafetyFinding {
  let report = @policy.evaluate_decision_policy(
    @policy.decision_policy_input(
      bundle.request.run_id,
      bundle.request.diagnosis,
      bundle.request.decision,
    ),
  )
  if report.allowed {
    safety_finding(
      bundle.request.run_id,
      DecisionPolicyBoundary,
      Pass,
      "decision-policy-report",
      report.summary,
    )
  } else {
    safety_finding(
      bundle.request.run_id,
      DecisionPolicyBoundary,
      Fail,
      "decision-policy-report",
      report.summary,
    )
  }
}

///|
fn context_budget_finding(
  bundle : @workflow.AnalysisRunBundle,
) -> SafetyFinding {
  match bundle.projection {
    Some(projection) =>
      if projection.context_budget.ok {
        safety_finding(
          bundle.request.run_id,
          ContextBudgetWithinWindow,
          Pass,
          "context-budget-report",
          projection.context_budget.summary,
        )
      } else {
        safety_finding(
          bundle.request.run_id,
          ContextBudgetWithinWindow,
          Fail,
          "context-budget-report",
          projection.context_budget.summary,
        )
      }
    None =>
      safety_finding(
        bundle.request.run_id,
        ContextBudgetWithinWindow,
        Pass,
        "context-budget-report",
        "context budget waits for prompt assembly",
      )
  }
}

///|
fn book_commit_finding(bundle : @workflow.AnalysisRunBundle) -> SafetyFinding {
  match bundle.book_commit {
    Some(report) =>
      if report.status is CommitReady {
        safety_finding(
          bundle.request.run_id,
          BookCommitCompleteness,
          Pass,
          "book-commit-report",
          report.summary,
        )
      } else {
        safety_finding(
          bundle.request.run_id,
          BookCommitCompleteness,
          Fail,
          "book-commit-report",
          report.summary,
        )
      }
    None =>
      safety_finding(
        bundle.request.run_id,
        BookCommitCompleteness,
        Pass,
        "book-commit-report",
        "book commit waits for completed run artifacts",
      )
  }
}

///|
fn secret_redaction_boundary_finding(
  bundle : @workflow.AnalysisRunBundle,
) -> SafetyFinding {
  let report = prepare_redaction_audit(bundle)
  if report.ok {
    safety_finding(
      bundle.request.run_id,
      SecretRedactionBoundary,
      Pass,
      "redaction-audit-report",
      report.summary,
    )
  } else {
    safety_finding(
      bundle.request.run_id,
      SecretRedactionBoundary,
      Fail,
      "redaction-audit-report",
      report.summary,
    )
  }
}

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

///|
fn public_export_redaction_finding(
  bundle : @workflow.AnalysisRunBundle,
) -> SafetyFinding {
  let manifest = @export.prepare_export_manifest(bundle, profile=PublicSummary)
  let unsafe_item = manifest.items.any(fn(item) {
    raw_model_schema(item.schema_id) || !item.public
  })
  if manifest.includes_raw_model_exchange || unsafe_item {
    safety_finding(
      bundle.request.run_id,
      PublicExportRedaction,
      Fail,
      "export.public-summary",
      "public export includes raw prompts, model exchange, or private items",
    )
  } else {
    safety_finding(
      bundle.request.run_id,
      PublicExportRedaction,
      Pass,
      "export.public-summary",
      "public export omits prompt packets, model requests, and model responses",
    )
  }
}

///|
fn replay_without_live_market_finding(
  bundle : @workflow.AnalysisRunBundle,
) -> SafetyFinding {
  let replay_plan = @replay.prepare_replay_plan(bundle)
  if replay_plan.live_market_required {
    safety_finding(
      bundle.request.run_id,
      ReplayWithoutLiveMarket,
      Fail,
      "replay-plan.live_market_required",
      "replay requires live market data",
    )
  } else {
    safety_finding(
      bundle.request.run_id,
      ReplayWithoutLiveMarket,
      Pass,
      "replay-plan.live_market_required",
      "replay is planned over persisted MoonBook evidence",
    )
  }
}

///|
fn owner_allowed(owner : @pack.PackOwner) -> Bool {
  owner is MoonGate ||
  owner is MoonClaw ||
  owner is MoonBook ||
  owner is Moondesk ||
  owner is PriceAction
}

///|
fn suite_ownership_finding(
  run_id : @domain.RunId,
  manifest : @pack.PackManifest,
) -> SafetyFinding {
  let invalid = manifest.tools.any(fn(tool) { !owner_allowed(tool.owner) })
  if invalid {
    safety_finding(
      run_id,
      SuiteOwnershipBoundary,
      Fail,
      "pack.tools.owner",
      "a tool is outside the declared MoonSuite ownership boundaries",
    )
  } else {
    safety_finding(
      run_id,
      SuiteOwnershipBoundary,
      Pass,
      "pack.tools.owner",
      "all tools are owned by MoonGate, MoonClaw, MoonBook, Moondesk, or PriceAction",
    )
  }
}

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

///|
pub fn prepare_safety_report(
  bundle : @workflow.AnalysisRunBundle,
  manifest? : @pack.PackManifest = @pack.price_action_manifest(),
) -> SafetyReport {
  let run_id = bundle.request.run_id
  let findings = [
    no_broker_execution_finding(run_id, manifest),
    decision_policy_finding(bundle),
    context_budget_finding(bundle),
    book_commit_finding(bundle),
    secret_redaction_boundary_finding(bundle),
    public_export_redaction_finding(bundle),
    replay_without_live_market_finding(bundle),
    suite_ownership_finding(run_id, manifest),
  ]
  { run_id, ok: report_ok(findings), findings }
}