///|
pub(all) enum OperationsGate {
  SuiteHealthReady
  PrimaryWorkflowReady
  RollbackMonitoringReady
  ReplayExportReady
  ResilienceEvidenceReady
  OperatorObservabilityReady
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) enum OperationsStatus {
  OperationsPass
  OperationsBlocked
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct OperationsFinding {
  gate : OperationsGate
  status : OperationsStatus
  evidence_path : String
  message : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct OperationsReportInput {
  product_status : @product.MoonfishProductStatus
  release_certificate : @release.ReleaseCertificate
  rollback_window_report : @rollback.RollbackWindowReport
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct OperationsReadinessReport {
  ready : Bool
  run_id : String
  operations_path : String
  pass_count : Int
  blocked_count : Int
  findings : Array[OperationsFinding]
  summary : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub fn operations_report_input(
  product_status : @product.MoonfishProductStatus,
  release_certificate : @release.ReleaseCertificate,
  rollback_window_report : @rollback.RollbackWindowReport,
) -> OperationsReportInput {
  { product_status, release_certificate, rollback_window_report }
}

///|
pub fn operations_finding(
  gate : OperationsGate,
  status : OperationsStatus,
  evidence_path : String,
  message : String,
) -> OperationsFinding {
  { gate, status, evidence_path, message }
}

///|
fn acceptance_pass(
  status : @product.MoonfishProductStatus,
  gate : @acceptance.AcceptanceGate,
) -> Bool {
  status.acceptance_report.findings.any(fn(finding) {
    finding.gate == gate && finding.status is Pass
  })
}

///|
fn release_pass(
  certificate : @release.ReleaseCertificate,
  gate : @release.ReleaseGate,
) -> Bool {
  certificate.findings.any(fn(finding) {
    finding.gate == gate && finding.status is ReleasePass
  })
}

///|
fn rollback_pass(
  report : @rollback.RollbackWindowReport,
  gate : @rollback.RollbackWindowGate,
) -> Bool {
  report.findings.any(fn(finding) {
    finding.gate == gate && finding.status is RollbackPass
  })
}

///|
fn suite_health_finding(
  status : @product.MoonfishProductStatus,
) -> OperationsFinding {
  let gateway = status.workspace.plan.gateway
  if status.settings_plan.review_count == 0 &&
    status.settings_plan.provider_secret_redacted &&
    gateway.openai_base_url != "" &&
    gateway.default_model != "" &&
    !gateway.usage.quota_exhausted &&
    gateway.contracts.all(fn(contract) { contract.ready }) &&
    acceptance_pass(status, ModelDiscovery) {
    operations_finding(
      SuiteHealthReady,
      OperationsPass,
      status.settings_plan.suite_status.status_path,
      "MoonGate gateway, model catalog, quota state, and integration contracts are ready",
    )
  } else {
    operations_finding(
      SuiteHealthReady,
      OperationsBlocked,
      "suite-status-ref",
      "suite model discovery or migrated settings evidence is incomplete",
    )
  }
}

///|
fn primary_workflow_finding(
  status : @product.MoonfishProductStatus,
  certificate : @release.ReleaseCertificate,
) -> OperationsFinding {
  if certificate.ready &&
    status.acceptance_report.passed &&
    status.readiness_report.ready &&
    status.cutover_plan.ready_to_cutover &&
    status.handoff_report.ready &&
    status.decommission_report.ready &&
    release_pass(certificate, ProductStatusReady) &&
    release_pass(certificate, RehearsalReady) &&
    release_pass(certificate, SuitePackComplete) {
    operations_finding(
      PrimaryWorkflowReady,
      OperationsPass,
      certificate.release_path,
      "release evidence keeps Moonfish as the standalone primary workflow",
    )
  } else {
    operations_finding(
      PrimaryWorkflowReady,
      OperationsBlocked,
      "release-certificate",
      "primary workflow evidence is blocked or incomplete",
    )
  }
}

///|
fn rollback_monitoring_finding(
  report : @rollback.RollbackWindowReport,
) -> OperationsFinding {
  if report.ready &&
    report.rollback_days >= 1 &&
    report.legacy_app_ref == "../paa" &&
    rollback_pass(report, WindowConfigured) &&
    rollback_pass(report, LegacyReadOnly) &&
    rollback_pass(report, EscalationPathReady) {
    operations_finding(
      RollbackMonitoringReady,
      OperationsPass,
      "records/rollback-windows/\{report.run_id}.json",
      "rollback monitoring, escalation, and legacy read-only boundaries are active",
    )
  } else {
    operations_finding(
      RollbackMonitoringReady,
      OperationsBlocked,
      "rollback-window-report",
      "rollback monitoring evidence is incomplete",
    )
  }
}

///|
fn replay_export_finding(
  status : @product.MoonfishProductStatus,
  certificate : @release.ReleaseCertificate,
  rollback_report : @rollback.RollbackWindowReport,
) -> OperationsFinding {
  if status.workspace.replay_plan.can_replay &&
    !status.workspace.replay_plan.live_market_required &&
    status.workspace.export_manifest.item_count > 0 &&
    status.workspace.export_manifest.destination_path != "" &&
    release_pass(certificate, ExportEvidenceReady) &&
    rollback_pass(rollback_report, ReplayAndExportReady) {
    operations_finding(
      ReplayExportReady,
      OperationsPass,
      status.workspace.export_manifest.destination_path,
      "persisted evidence supports replay and export without live market data",
    )
  } else {
    operations_finding(
      ReplayExportReady,
      OperationsBlocked,
      "export-manifest",
      "replay/export evidence is incomplete for day-2 operation",
    )
  }
}

///|
fn resilience_finding(
  status : @product.MoonfishProductStatus,
) -> OperationsFinding {
  if acceptance_pass(status, RoutineCancellation) &&
    acceptance_pass(status, ProviderFailureHandling) &&
    acceptance_pass(status, RecordIntegrity) &&
    acceptance_pass(status, SafetyAndRedaction) {
    operations_finding(
      ResilienceEvidenceReady,
      OperationsPass,
      "acceptance-report",
      "cancellation, provider failure, record integrity, and safety gates pass",
    )
  } else {
    operations_finding(
      ResilienceEvidenceReady,
      OperationsBlocked,
      "acceptance-report",
      "resilience acceptance evidence is incomplete",
    )
  }
}

///|
fn operator_observability_finding(
  status : @product.MoonfishProductStatus,
) -> OperationsFinding {
  if acceptance_pass(status, AppToolContract) &&
    acceptance_pass(status, OperatorHandoffReadiness) &&
    acceptance_pass(status, MoondeskAppSmoke) &&
    status.workspace.history.total_count > 0 &&
    status.workspace.run_view.event_count > 0 &&
    status.workspace.app_tool_manifest.redacted_binding_count >= 3 &&
    status.workspace.app_tool_manifest.surfaces.any(fn(surface) {
      surface.id == "run-analysis" && surface.enabled
    }) &&
    status.workspace.app_tool_manifest.surfaces.any(fn(surface) {
      surface.id == "replay-run" && surface.enabled
    }) &&
    status.workspace.app_tool_manifest.surfaces.any(fn(surface) {
      surface.id == "export-run" && surface.enabled
    }) {
    operations_finding(
      OperatorObservabilityReady,
      OperationsPass,
      "moondesk-app-smoke-report",
      "Moondesk surfaces expose run, replay, export, history, events, and redacted debug evidence",
    )
  } else {
    operations_finding(
      OperatorObservabilityReady,
      OperationsBlocked,
      "moondesk-app-tool-manifest",
      "operator observability surface is incomplete",
    )
  }
}

///|
fn count_status(
  findings : Array[OperationsFinding],
  status : OperationsStatus,
) -> Int {
  findings.fold(init=0, fn(count, finding) {
    if finding.status == status {
      count + 1
    } else {
      count
    }
  })
}

///|
pub fn prepare_operations_readiness_report(
  input : OperationsReportInput,
) -> OperationsReadinessReport {
  let status = input.product_status
  let certificate = input.release_certificate
  let rollback_report = input.rollback_window_report
  let findings = [
    suite_health_finding(status),
    primary_workflow_finding(status, certificate),
    rollback_monitoring_finding(rollback_report),
    replay_export_finding(status, certificate, rollback_report),
    resilience_finding(status),
    operator_observability_finding(status),
  ]
  let blocked_count = count_status(findings, OperationsBlocked)
  let pass_count = count_status(findings, OperationsPass)
  let ready = blocked_count == 0
  let run_id = status.workspace.bundle.request.run_id
  {
    ready,
    run_id,
    operations_path: "records/operations/\{run_id}.json",
    pass_count,
    blocked_count,
    findings,
    summary: if ready {
      "operations readiness ready with \{pass_count}/\{findings.length()} gate(s); Moonfish can run day-2 without PA Agent"
    } else {
      "operations readiness blocked by \{blocked_count} gate(s)"
    },
  }
}