///|
pub(all) enum AppToolSurfaceKind {
  Control
  Panel
  Action
  DataBinding
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) enum AppToolControlKind {
  DataSourceSelect
  SymbolInput
  TimeframeSelect
  LimitInput
  RunButton
  CancelButton
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) enum AppToolBindingKind {
  SuiteStatus
  MarketRequest
  MarketRefreshPlan
  MarketIngestInput
  RoutineEvents
  Stage1Json
  Stage2Json
  StrategyRouting
  ExperienceMemory
  DecisionPolicy
  StructureLevels
  ContextBudget
  ValidationRetry
  PromptPackets
  RawModelExchange
  BookCommit
  RedactionAudit
  CancellationReport
  ProviderFailureReport
  RecordIntegrityReport
  AnalysisRecord
  ChartFrame
  FollowUpSessionPlan
  FollowUpTurns
  FollowUpResponse
  ExportManifest
  ReplayPlan
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct AppToolControl {
  id : String
  kind : AppToolControlKind
  binding : AppToolBindingKind
  required : Bool
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct AppToolBinding {
  id : String
  kind : AppToolBindingKind
  schema_id : String
  source_path : String
  redacted : Bool
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct AppToolSurface {
  id : String
  kind : AppToolSurfaceKind
  label : String
  enabled : Bool
  binding_ids : Array[String]
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct MoondeskAppToolManifest {
  id : String
  mount_path : String
  display_name : String
  run_id : @domain.RunId
  controls : Array[AppToolControl]
  bindings : Array[AppToolBinding]
  surfaces : Array[AppToolSurface]
  required_tools : Array[String]
  redacted_binding_count : Int
  summary : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub fn app_tool_control(
  id : String,
  kind : AppToolControlKind,
  binding : AppToolBindingKind,
  required? : Bool = true,
) -> AppToolControl {
  { id, kind, binding, required }
}

///|
pub fn app_tool_binding(
  id : String,
  kind : AppToolBindingKind,
  schema_id : String,
  source_path : String,
  redacted? : Bool = false,
) -> AppToolBinding {
  { id, kind, schema_id, source_path, redacted }
}

///|
pub fn app_tool_surface(
  id : String,
  kind : AppToolSurfaceKind,
  label : String,
  binding_ids : Array[String],
  enabled? : Bool = true,
) -> AppToolSurface {
  { id, kind, label, enabled, binding_ids }
}

///|
fn binding_present(bindings : Array[AppToolBinding], id : String) -> Bool {
  bindings.any(fn(binding) { binding.id == id })
}

///|
fn push_surface_if_missing(
  surfaces : Array[AppToolSurface],
  surface : AppToolSurface,
) -> Unit {
  if !surfaces.any(fn(item) { item.id == surface.id }) {
    surfaces.push(surface)
  }
}

///|
fn binding_path(view : OperatorRunView, file : String) -> String {
  "apps/moondesk-price-action/run-views/\{view.run_id}/\{file}.json"
}

///|
fn default_controls() -> Array[AppToolControl] {
  [
    app_tool_control("data-source", DataSourceSelect, MarketRequest),
    app_tool_control("symbol", SymbolInput, MarketRequest),
    app_tool_control("timeframe", TimeframeSelect, MarketRequest),
    app_tool_control("limit", LimitInput, MarketRequest),
    app_tool_control("run", RunButton, RoutineEvents),
    app_tool_control("cancel", CancelButton, RoutineEvents, required=false),
  ]
}

///|
fn default_bindings(view : OperatorRunView) -> Array[AppToolBinding] {
  let bindings = [
    app_tool_binding(
      "suite-status",
      SuiteStatus,
      "suite-status-ref",
      @model.moonsuite_suite_status_path(),
      redacted=true,
    ),
    app_tool_binding(
      "market-request",
      MarketRequest,
      "market-source-request",
      binding_path(view, "market-request"),
    ),
    app_tool_binding(
      "market-refresh",
      MarketRefreshPlan,
      "market-refresh-plan",
      binding_path(view, "market-refresh"),
    ),
    app_tool_binding(
      "routine-events",
      RoutineEvents,
      "routine-event-log",
      "raw/run-events/\{view.run_id}.json",
    ),
    app_tool_binding(
      "stage1-json",
      Stage1Json,
      "stage1-diagnosis",
      "records/analyses/\{view.run_id}.json",
    ),
    app_tool_binding(
      "stage2-json",
      Stage2Json,
      "stage2-decision",
      "records/analyses/\{view.run_id}.json",
    ),
    app_tool_binding(
      "strategy-routing",
      StrategyRouting,
      "strategy-file-list",
      binding_path(view, "strategy-routing"),
    ),
    app_tool_binding(
      "experience-memory",
      ExperienceMemory,
      "experience-memory-selection",
      "records/memory-selections/\{view.run_id}.json",
    ),
    app_tool_binding(
      "decision-policy",
      DecisionPolicy,
      "decision-policy-report",
      "records/policies/\{view.run_id}.json",
    ),
    app_tool_binding(
      "structure-levels",
      StructureLevels,
      "structure-level-frame",
      "records/structure-levels/\{view.run_id}.json",
    ),
    app_tool_binding(
      "context-budget",
      ContextBudget,
      "context-budget-report",
      "records/context-budgets/\{view.run_id}.json",
    ),
    app_tool_binding(
      "validation-retry",
      ValidationRetry,
      "retry-decision",
      binding_path(view, "validation-retry"),
    ),
    app_tool_binding(
      "prompt-packets",
      PromptPackets,
      "prompt-packet",
      "raw/prompts/\{view.run_id}",
      redacted=true,
    ),
    app_tool_binding(
      "raw-model-exchange",
      RawModelExchange,
      "model-call-response",
      "raw/model-replies/\{view.run_id}",
      redacted=true,
    ),
    app_tool_binding(
      "book-commit",
      BookCommit,
      "book-commit-report",
      "records/book-commits/\{view.run_id}.json",
    ),
    app_tool_binding(
      "redaction-audit",
      RedactionAudit,
      "redaction-audit-report",
      "records/redaction-audits/\{view.run_id}.json",
    ),
    app_tool_binding(
      "cancellation-report",
      CancellationReport,
      "cancellation-report",
      "records/cancellations/\{view.run_id}.json",
    ),
    app_tool_binding(
      "provider-failure",
      ProviderFailureReport,
      "provider-failure-report",
      "records/provider-failures/\{view.run_id}.json",
    ),
    app_tool_binding(
      "record-integrity",
      RecordIntegrityReport,
      "record-integrity-report",
      "records/integrity/\{view.run_id}.json",
    ),
    app_tool_binding(
      "analysis-record",
      AnalysisRecord,
      "analysis-record",
      "records/analyses/\{view.run_id}.json",
    ),
    app_tool_binding(
      "follow-up-session",
      FollowUpSessionPlan,
      "followup-session-plan",
      "records/followups/\{view.run_id}/session-plan.json",
    ),
    app_tool_binding(
      "follow-up",
      FollowUpTurns,
      "followup-context",
      "records/followups/\{view.run_id}.json",
    ),
    app_tool_binding(
      "follow-up-response",
      FollowUpResponse,
      "followup-response",
      "records/followups/\{view.run_id}/responses.json",
    ),
    app_tool_binding(
      "export-manifest",
      ExportManifest,
      "export-manifest",
      "records/exports/\{view.run_id}.json",
    ),
    app_tool_binding(
      "replay-plan",
      ReplayPlan,
      "replay-plan",
      "records/replays/\{view.run_id}.json",
    ),
  ]
  if view.status is AwaitingMarketData {
    bindings.push(
      app_tool_binding(
        "market-ingest",
        MarketIngestInput,
        "market-ingest-input",
        binding_path(view, "market-ingest"),
      ),
    )
  }
  match view.chart_path {
    Some(path) =>
      bindings.push(
        app_tool_binding("chart-frame", ChartFrame, "chart-frame", path),
      )
    None => ()
  }
  bindings
}

///|
fn redacted_binding_count(bindings : Array[AppToolBinding]) -> Int {
  bindings.fold(init=0, fn(count, binding) {
    if binding.redacted {
      count + 1
    } else {
      count
    }
  })
}

///|
fn surface_from_panel(
  panel : OperatorPanel,
  view : OperatorRunView,
) -> AppToolSurface {
  match panel {
    DataSourcePanel =>
      app_tool_surface(
        "data-source-panel",
        Panel,
        "Data Source",
        if view.status is AwaitingMarketData {
          ["suite-status", "market-request", "market-refresh", "market-ingest"]
        } else {
          ["suite-status", "market-request", "market-refresh"]
        },
      )
    ChartPanel =>
      app_tool_surface(
        "chart-panel",
        Panel,
        "Chart",
        ["chart-frame", "structure-levels", "market-request"],
        enabled=binding_present(default_bindings(view), "chart-frame"),
      )
    DecisionPanel =>
      app_tool_surface("decision-panel", Panel, "Decision", [
        "stage1-json", "stage2-json", "strategy-routing", "experience-memory", "decision-policy",
        "structure-levels",
      ])
    EventStreamPanel =>
      app_tool_surface("event-stream-panel", Panel, "Events", [
        "routine-events", "book-commit", "cancellation-report", "provider-failure",
      ])
    PromptDebugPanel =>
      app_tool_surface("prompt-debug-panel", Panel, "Debug", [
        "prompt-packets", "context-budget", "raw-model-exchange", "validation-retry",
      ])
    ReviewPanel =>
      app_tool_surface("review-panel", Panel, "Review", [
        "validation-retry", "book-commit", "redaction-audit", "cancellation-report",
        "provider-failure", "record-integrity", "analysis-record",
      ])
    FollowUpPanel =>
      app_tool_surface("follow-up-panel", Panel, "Follow Up", [
        "follow-up-session", "follow-up", "follow-up-response", "analysis-record",
      ])
    ExportPanel =>
      app_tool_surface("export-panel", Panel, "Export", [
        "export-manifest", "replay-plan", "redaction-audit", "record-integrity",
      ])
  }
}

///|
fn surface_from_action(action : OperatorAction) -> AppToolSurface {
  match action {
    ConfigureDataSource =>
      app_tool_surface(
        "configure-data-source",
        Action,
        "Configure data source",
        ["market-request"],
      )
    SubmitMarketSnapshot =>
      app_tool_surface(
        "submit-market-snapshot",
        Action,
        "Submit market snapshot",
        ["market-ingest"],
      )
    RunAnalysis =>
      app_tool_surface("run-analysis", Action, "Run analysis", [
        "routine-events",
      ])
    InspectChart =>
      app_tool_surface("inspect-chart", Action, "Inspect chart", [
        "chart-frame", "structure-levels",
      ])
    InspectEvents =>
      app_tool_surface("inspect-events", Action, "Inspect events", [
        "routine-events",
      ])
    InspectPrompts =>
      app_tool_surface("inspect-prompts", Action, "Inspect prompts", [
        "prompt-packets", "context-budget", "raw-model-exchange",
      ])
    InspectReviews =>
      app_tool_surface("inspect-reviews", Action, "Inspect reviews", [
        "validation-retry", "analysis-record",
      ])
    StartFollowUp =>
      app_tool_surface("start-follow-up", Action, "Start follow-up", [
        "follow-up-session", "follow-up", "follow-up-response",
      ])
    ExportRun =>
      app_tool_surface("export-run", Action, "Export run", ["export-manifest"])
    ReplayRun =>
      app_tool_surface("replay-run", Action, "Replay run", ["replay-plan"])
  }
}

///|
fn required_tools() -> Array[String] {
  [
    "prepare_analysis_workspace", "prepare_market_refresh_plan", "prepare_context_budget_plan",
    "run_two_stage_routine", "fetch_kline_snapshot", "ingest_market_snapshot", "compute_structure_levels",
    "render_chart_frame", "prepare_book_commit_report", "render_operator_run_view",
    "render_run_history", "evaluate_decision_policy", "prepare_redaction_audit",
    "prepare_cancellation_report", "prepare_provider_failure_report", "prepare_record_integrity_report",
    "prepare_followup_context", "prepare_followup_session_plan", "prepare_replay_plan",
    "prepare_export_manifest", "select_experience_memories", "prepare_followup_response",
  ]
}

///|
fn app_tool_summary(manifest : MoondeskAppToolManifest) -> String {
  "moondesk app-tool exposes \{manifest.controls.length()} controls, \{manifest.surfaces.length()} surfaces, \{manifest.bindings.length()} bindings, and \{manifest.redacted_binding_count} redacted debug binding(s)"
}

///|
pub fn moondesk_app_tool_manifest(
  view : OperatorRunView,
) -> MoondeskAppToolManifest {
  let surfaces : Array[AppToolSurface] = []
  for panel in view.panels {
    push_surface_if_missing(surfaces, surface_from_panel(panel, view))
  }
  for action in view.actions {
    push_surface_if_missing(surfaces, surface_from_action(action))
  }
  let manifest : MoondeskAppToolManifest = {
    id: "moondesk-price-action",
    mount_path: "apps/moondesk-price-action",
    display_name: "Moonfish Price Action",
    run_id: view.run_id,
    controls: default_controls(),
    bindings: default_bindings(view),
    surfaces,
    required_tools: required_tools(),
    redacted_binding_count: redacted_binding_count(default_bindings(view)),
    summary: "",
  }
  { ..manifest, summary: app_tool_summary(manifest) }
}