///|
pub(all) struct RobotReadinessMetricView {
  metric_id : String
  label : String
  value : Int
  status : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct RobotReadinessEvidenceView {
  evidence_id : String
  label : String
  count : Int
  status : String
} derive(Debug, Eq, ToJson, FromJson)

///|
pub(all) struct RobotReadinessViewModel {
  view_id : String
  root : String
  title : String
  status : String
  ready : Bool
  validation_status : String
  blocker_count : Int
  warning_count : Int
  data_ref_count : Int
  next_action : String
  summary : String
  validation_artifact_id : String
  validation_manifest_path : String
  metrics : Array[RobotReadinessMetricView]
  evidence : Array[RobotReadinessEvidenceView]
} derive(Debug, Eq, ToJson, FromJson)

///|
fn readiness_count_status(value : Int) -> String {
  if value > 0 {
    "ready"
  } else {
    "missing"
  }
}

///|
fn readiness_metric(
  metric_id : String,
  label : String,
  value : Int,
) -> RobotReadinessMetricView {
  { metric_id, label, value, status: readiness_count_status(value) }
}

///|
fn readiness_evidence(
  evidence_id : String,
  label : String,
  count : Int,
) -> RobotReadinessEvidenceView {
  { evidence_id, label, count, status: readiness_count_status(count) }
}

///|
pub fn robot_readiness_view_model(
  readiness : @robot_catalog.RobotMigrationReadiness,
) -> RobotReadinessViewModel {
  {
    view_id: "ui/robot-migration-readiness/operator-view-v1",
    root: readiness.root,
    title: "Robot Migration Readiness",
    status: readiness.status,
    ready: readiness.ready,
    validation_status: @data_core.validation_status_label(
      readiness.validation_status,
    ),
    blocker_count: readiness.blocker_count,
    warning_count: readiness.warning_count,
    data_ref_count: readiness.data_ref_count,
    next_action: readiness.next_action,
    summary: readiness.summary,
    validation_artifact_id: readiness.validation_artifact.artifact_id,
    validation_manifest_path: readiness.validation_artifact.manifest_path,
    metrics: [
      readiness_metric("models", "models", readiness.model_count),
      readiness_metric("episodes", "episodes", readiness.episode_count),
      readiness_metric(
        "telemetry-streams",
        "telemetry streams",
        readiness.telemetry_stream_count,
      ),
      readiness_metric("gait-clips", "gait clips", readiness.gait_clip_count),
      readiness_metric(
        "gait-annotations",
        "gait annotations",
        readiness.gait_annotation_count,
      ),
      readiness_metric(
        "gait-alignments",
        "gait alignments",
        readiness.gait_alignment_count,
      ),
      readiness_metric("task-labels", "task labels", readiness.task_label_count),
      readiness_metric("rollouts", "rollout summaries", readiness.rollout_count),
    ],
    evidence: [
      readiness_evidence("signals", "signal refs", readiness.signal_ref_count),
      readiness_evidence("replays", "replay refs", readiness.replay_ref_count),
      readiness_evidence("quality", "quality refs", readiness.quality_ref_count),
      readiness_evidence(
        "telemetry",
        "telemetry refs",
        readiness.telemetry_ref_count,
      ),
      readiness_evidence("gait", "gait refs", readiness.gait_ref_count),
      readiness_evidence(
        "gait-annotations",
        "gait annotation refs",
        readiness.gait_annotation_ref_count,
      ),
      readiness_evidence(
        "gait-alignments",
        "gait alignment refs",
        readiness.gait_alignment_ref_count,
      ),
      readiness_evidence(
        "task-labels",
        "task label refs",
        readiness.task_label_ref_count,
      ),
      readiness_evidence(
        "rollouts",
        "rollout refs",
        readiness.rollout_ref_count,
      ),
    ],
  }
}

///|
pub fn robot_readiness_view_model_from_catalog_root(
  root : String,
) -> Result[RobotReadinessViewModel, CatalogBackedViewIssue] {
  let readiness = match
    @robot_catalog.robot_migration_readiness_from_root(root) {
    Ok(value) => value
    Err(error) =>
      return Err(
        catalog_backed_view_issue(error.code, error.path, error.message),
      )
  }
  Ok(robot_readiness_view_model(readiness))
}

///|
pub fn robot_readiness_catalog_json(
  root : String,
) -> Result[Json, CatalogBackedViewIssue] {
  let view = match robot_readiness_view_model_from_catalog_root(root) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  Ok(view.to_json())
}

///|
fn robot_metric_rows(metrics : Array[RobotReadinessMetricView]) -> String {
  let mut html = ""
  for metric in metrics {
    let row =
      $|
\{html_escape(metric.label)}\{html_escape(metric.metric_id)}
\{metric.value}
html += row } html } ///| fn robot_evidence_rows(evidence : Array[RobotReadinessEvidenceView]) -> String { let mut html = "" for item in evidence { let row = $|
\{html_escape(item.label)}\{html_escape(item.evidence_id)}
\{item.count}
html += row } html } ///| pub fn render_robot_readiness_html(view : RobotReadinessViewModel) -> String { let title = html_escape(view.title) let status = html_escape(view.status) let next_action = html_escape(view.next_action) let summary = html_escape(view.summary) let validation = html_escape(view.validation_status) let validation_path = html_escape(view.validation_manifest_path) let view_json = view.to_json().stringify(indent=2) let html = $| $| $| $| $| $|MoonMoon - \{title} $|\{app_styles()} $| $| $| $|
$|
$|

\{title}

\{summary}

\{status}
$|

robot data root

\{view.data_ref_count}cataloged data refs, next action: \{next_action}
validation\{validation}
blockers\{view.blocker_count}
warnings\{view.warning_count}
ready\{if view.ready { "yes" } else { "no" }}
$|

dataset families

\{robot_metric_rows(view.metrics)}
$|
$| $|
$| $| html } ///| pub fn robot_readiness_catalog_html( root : String, ) -> Result[String, CatalogBackedViewIssue] { let view = match robot_readiness_view_model_from_catalog_root(root) { Ok(value) => value Err(error) => return Err(error) } Ok(render_robot_readiness_html(view)) }