///|
/// Lifecycle state of a production processing job.
pub enum ProcessingJobState {
  JobQueued
  JobRunning
  JobCompleted
  JobDegraded
  JobFailed
}

///|
/// A compact processing job status.
pub struct ProcessingJobStatus {
  job_id : String
  state : ProcessingJobState
  processed_samples : Int
  total_samples : Int
  score : Double
  message : String
}

///|
/// Construct a processing job status.
pub fn ProcessingJobStatus::new(
  job_id : String,
  state : ProcessingJobState,
  processed_samples : Int,
  total_samples : Int,
  score : Double,
  message : String,
) -> ProcessingJobStatus {
  { job_id, state, processed_samples, total_samples, score, message }
}

///|
/// Return all lifecycle states for UI configuration.
pub fn supported_processing_job_states() -> Array[ProcessingJobState] {
  [JobQueued, JobRunning, JobCompleted, JobDegraded, JobFailed]
}

///|
/// Return a stable lifecycle state label.
pub fn processing_job_state_name(state : ProcessingJobState) -> String {
  match state {
    JobQueued => "queued"
    JobRunning => "running"
    JobCompleted => "completed"
    JobDegraded => "degraded"
    JobFailed => "failed"
  }
}

///|
/// Calculate completion fraction for a processing job.
pub fn processing_completion(status : ProcessingJobStatus) -> Double {
  if status.total_samples <= 0 {
    0.0
  } else {
    (status.processed_samples.max(0).to_double() /
    status.total_samples.to_double()).min(1.0)
  }
}

///|
/// Format job status for a health endpoint.
pub fn processing_job_status_text(status : ProcessingJobStatus) -> String {
  "job=" +
  status.job_id +
  " state=" +
  processing_job_state_name(status.state) +
  " processed=" +
  status.processed_samples.to_string() +
  " total=" +
  status.total_samples.to_string() +
  " score=" +
  status.score.to_string() +
  " message=" +
  status.message
}