///|
pub(all) enum MoondeskAppSmokeCheck {
  RemovableMount
  BindingResolution
  CompletedOperatorWorkflow
  ExternalSnapshotIngest
  RedactedDebugEvidence
  MoonBookBackedState
  RequiredToolCoverage
} derive(Debug, Eq, ToJson, FromJson)

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

///|
pub(all) struct MoondeskAppSmokeFinding {
  check : MoondeskAppSmokeCheck
  status : MoondeskAppSmokeStatus
  evidence_path : String
  message : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct MoondeskAppSmokeInput {
  completed_workspace : @workspace.AnalysisWorkspace
  awaiting_workspace : @workspace.AnalysisWorkspace
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct MoondeskAppSmokeReport {
  ready : Bool
  completed_run_id : @domain.RunId
  awaiting_run_id : @domain.RunId
  finding_count : Int
  pass_count : Int
  needs_work_count : Int
  findings : Array[MoondeskAppSmokeFinding]
  summary : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub fn moondesk_app_smoke_input(
  completed_workspace : @workspace.AnalysisWorkspace,
  awaiting_workspace : @workspace.AnalysisWorkspace,
) -> MoondeskAppSmokeInput {
  { completed_workspace, awaiting_workspace }
}

///|
pub fn moondesk_app_smoke_finding(
  check : MoondeskAppSmokeCheck,
  status : MoondeskAppSmokeStatus,
  evidence_path : String,
  message : String,
) -> MoondeskAppSmokeFinding {
  { check, status, evidence_path, message }
}

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

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

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

///|
fn enabled_surface(
  manifest : @app.MoondeskAppToolManifest,
  surface_id : String,
) -> Bool {
  manifest.surfaces.any(fn(surface) {
    surface.id == surface_id && surface.enabled
  })
}

///|
fn required_tool(
  manifest : @app.MoondeskAppToolManifest,
  tool : String,
) -> Bool {
  manifest.required_tools.contains(tool)
}

///|
fn all_surface_bindings_resolve(
  manifest : @app.MoondeskAppToolManifest,
) -> Bool {
  manifest.surfaces.all(fn(surface) {
    surface.binding_ids.all(fn(binding_id) {
      binding_declared(manifest, binding_id)
    })
  })
}

///|
fn redacted_count(manifest : @app.MoondeskAppToolManifest) -> Int {
  manifest.bindings.fold(init=0, fn(count, binding) {
    if binding.redacted {
      count + 1
    } else {
      count
    }
  })
}

///|
fn allowed_state_path(path : String) -> Bool {
  path.has_prefix("apps/moondesk-price-action/") ||
  path.has_prefix("records/") ||
  path.has_prefix("raw/") ||
  path.has_prefix(".moonsuite/")
}

///|
fn removable_mount_finding(
  input : MoondeskAppSmokeInput,
) -> MoondeskAppSmokeFinding {
  let completed = input.completed_workspace.app_tool_manifest
  let awaiting = input.awaiting_workspace.app_tool_manifest
  if completed.id == "moondesk-price-action" &&
    awaiting.id == "moondesk-price-action" &&
    completed.mount_path == "apps/moondesk-price-action" &&
    awaiting.mount_path == "apps/moondesk-price-action" &&
    completed.display_name != "" &&
    awaiting.display_name != "" &&
    completed.bindings.all(fn(binding) {
      allowed_state_path(binding.source_path)
    }) &&
    awaiting.bindings.all(fn(binding) {
      allowed_state_path(binding.source_path)
    }) {
    moondesk_app_smoke_finding(
      RemovableMount,
      Pass,
      "moondesk-app-tool-manifest",
      "app-tool mounts under the removable price-action app path and stores state in MoonBook or app projections",
    )
  } else {
    moondesk_app_smoke_finding(
      RemovableMount,
      NeedsWork,
      "moondesk-app-tool-manifest",
      "app-tool mount or binding paths would require hidden Moondesk core state",
    )
  }
}

///|
fn binding_resolution_finding(
  input : MoondeskAppSmokeInput,
) -> MoondeskAppSmokeFinding {
  if all_surface_bindings_resolve(input.completed_workspace.app_tool_manifest) &&
    all_surface_bindings_resolve(input.awaiting_workspace.app_tool_manifest) {
    moondesk_app_smoke_finding(
      BindingResolution,
      Pass,
      "moondesk-app-tool-manifest.surfaces",
      "every enabled operator surface resolves to declared app-tool bindings",
    )
  } else {
    moondesk_app_smoke_finding(
      BindingResolution,
      NeedsWork,
      "moondesk-app-tool-manifest.surfaces",
      "one or more operator surfaces reference undeclared bindings",
    )
  }
}

///|
fn completed_workflow_finding(
  input : MoondeskAppSmokeInput,
) -> MoondeskAppSmokeFinding {
  let workspace = input.completed_workspace
  let manifest = workspace.app_tool_manifest
  let view = workspace.run_view
  if workspace.bundle.status is Completed &&
    view.chart_path is Some(_) &&
    view.event_count > 0 &&
    view.book_artifact_count > 0 &&
    view.followup_topic_count > 0 &&
    view.replay_available &&
    view.export_item_count > 0 &&
    enabled_surface(manifest, "run-analysis") &&
    enabled_surface(manifest, "inspect-chart") &&
    enabled_surface(manifest, "inspect-events") &&
    enabled_surface(manifest, "inspect-prompts") &&
    enabled_surface(manifest, "start-follow-up") &&
    enabled_surface(manifest, "export-run") &&
    enabled_surface(manifest, "replay-run") {
    moondesk_app_smoke_finding(
      CompletedOperatorWorkflow,
      Pass,
      "apps/moondesk-price-action/run-views/\{view.run_id}",
      "completed run exposes analysis, chart, event, prompt, follow-up, export, and replay surfaces",
    )
  } else {
    moondesk_app_smoke_finding(
      CompletedOperatorWorkflow,
      NeedsWork,
      "apps/moondesk-price-action/run-views/\{view.run_id}",
      "completed run does not expose the full operator workflow",
    )
  }
}

///|
fn external_ingest_finding(
  input : MoondeskAppSmokeInput,
) -> MoondeskAppSmokeFinding {
  let workspace = input.awaiting_workspace
  let manifest = workspace.app_tool_manifest
  let view = workspace.run_view
  if workspace.bundle.status is AwaitingMarketData &&
    view.blocking_review_count > 0 &&
    view.chart_path is None &&
    enabled_surface(manifest, "configure-data-source") &&
    enabled_surface(manifest, "submit-market-snapshot") &&
    binding_with_schema(manifest, "market-ingest", "market-ingest-input") {
    moondesk_app_smoke_finding(
      ExternalSnapshotIngest,
      Pass,
      "apps/moondesk-price-action/run-views/\{view.run_id}/market-ingest.json",
      "external-data run blocks for review and exposes a typed snapshot ingest action",
    )
  } else {
    moondesk_app_smoke_finding(
      ExternalSnapshotIngest,
      NeedsWork,
      "apps/moondesk-price-action/run-views/\{view.run_id}/market-ingest.json",
      "external-data run cannot be completed through a typed Moondesk ingest surface",
    )
  }
}

///|
fn redacted_debug_finding(
  input : MoondeskAppSmokeInput,
) -> MoondeskAppSmokeFinding {
  let manifest = input.completed_workspace.app_tool_manifest
  if manifest.redacted_binding_count == redacted_count(manifest) &&
    redacted_binding(manifest, "suite-status") &&
    redacted_binding(manifest, "prompt-packets") &&
    redacted_binding(manifest, "raw-model-exchange") {
    moondesk_app_smoke_finding(
      RedactedDebugEvidence,
      Pass,
      "moondesk-app-tool-manifest.bindings",
      "suite status, prompt packets, and raw model exchange stay redacted in app-tool debug bindings",
    )
  } else {
    moondesk_app_smoke_finding(
      RedactedDebugEvidence,
      NeedsWork,
      "moondesk-app-tool-manifest.bindings",
      "sensitive app-tool debug evidence is not consistently redacted",
    )
  }
}

///|
fn moonbook_state_finding(
  input : MoondeskAppSmokeInput,
) -> MoondeskAppSmokeFinding {
  let manifest = input.completed_workspace.app_tool_manifest
  if binding_with_schema(manifest, "analysis-record", "analysis-record") &&
    binding_with_schema(manifest, "book-commit", "book-commit-report") &&
    binding_with_schema(manifest, "record-integrity", "record-integrity-report") &&
    binding_with_schema(manifest, "follow-up-session", "followup-session-plan") &&
    binding_with_schema(manifest, "follow-up-response", "followup-response") &&
    binding_with_schema(manifest, "export-manifest", "export-manifest") &&
    binding_with_schema(manifest, "replay-plan", "replay-plan") &&
    input.completed_workspace.book_artifact_count > 0 {
    moondesk_app_smoke_finding(
      MoonBookBackedState,
      Pass,
      "records/analyses/\{input.completed_workspace.run_view.run_id}.json",
      "operator state is backed by MoonBook records, commits, follow-up, export, replay, and integrity evidence",
    )
  } else {
    moondesk_app_smoke_finding(
      MoonBookBackedState,
      NeedsWork,
      "records/analyses/\{input.completed_workspace.run_view.run_id}.json",
      "operator workflow depends on missing MoonBook-backed evidence",
    )
  }
}

///|
fn required_tool_finding(
  input : MoondeskAppSmokeInput,
) -> MoondeskAppSmokeFinding {
  let manifest = input.completed_workspace.app_tool_manifest
  if required_tool(manifest, "run_two_stage_routine") &&
    required_tool(manifest, "ingest_market_snapshot") &&
    required_tool(manifest, "render_operator_run_view") &&
    required_tool(manifest, "render_run_history") &&
    required_tool(manifest, "prepare_followup_session_plan") &&
    required_tool(manifest, "prepare_followup_response") &&
    required_tool(manifest, "prepare_export_manifest") &&
    required_tool(manifest, "prepare_replay_plan") &&
    required_tool(manifest, "prepare_record_integrity_report") {
    moondesk_app_smoke_finding(
      RequiredToolCoverage,
      Pass,
      "moondesk-app-tool-manifest.required_tools",
      "app-tool declares the MoonClaw, MoonBook, and Moondesk tools needed for the operator path",
    )
  } else {
    moondesk_app_smoke_finding(
      RequiredToolCoverage,
      NeedsWork,
      "moondesk-app-tool-manifest.required_tools",
      "app-tool required tools do not cover the operator path",
    )
  }
}

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

///|
pub fn prepare_moondesk_app_smoke_report(
  input : MoondeskAppSmokeInput,
) -> MoondeskAppSmokeReport {
  let findings = [
    removable_mount_finding(input),
    binding_resolution_finding(input),
    completed_workflow_finding(input),
    external_ingest_finding(input),
    redacted_debug_finding(input),
    moonbook_state_finding(input),
    required_tool_finding(input),
  ]
  let needs_work_count = count_status(findings, NeedsWork)
  let pass_count = count_status(findings, Pass)
  let ready = needs_work_count == 0
  {
    ready,
    completed_run_id: input.completed_workspace.run_view.run_id,
    awaiting_run_id: input.awaiting_workspace.run_view.run_id,
    finding_count: findings.length(),
    pass_count,
    needs_work_count,
    findings,
    summary: if ready {
      "moondesk app-tool smoke passed \{pass_count}/\{findings.length()} checks"
    } else {
      "moondesk app-tool smoke has \{needs_work_count} check(s) needing work"
    },
  }
}