///|
/// A deterministic runbook step used to guide operators through a response.
pub(all) struct RunbookStep {
  name : String
  event : String
  owner : String
  required : Bool
}

///|
/// A response runbook selected by incident severity.
pub(all) struct IncidentRunbook {
  title : String
  steps : Array[RunbookStep]
}

///|
fn required_step(name : String, event : String, owner : String) -> RunbookStep {
  { name, event, owner, required: true }
}

///|
fn optional_step(name : String, event : String, owner : String) -> RunbookStep {
  { name, event, owner, required: false }
}

///|
/// Returns the standard response runbook for a severity level.
pub fn runbook_for_severity(severity : Int) -> IncidentRunbook {
  if severity >= 3 {
    {
      title: "SEV-1 critical response",
      steps: [
        required_step("Acknowledge alert", "Acknowledge", "on-call"),
        required_step("Escalate commander", "Escalate", "incident-commander"),
        required_step(
          "Assign commander", "AssignCommander", "incident-commander",
        ),
        required_step("Diagnose impact", "Diagnose", "service-owner"),
        required_step("Mitigate customer impact", "Mitigate", "service-owner"),
        required_step("Verify recovery", "Verify", "observability"),
        optional_step("Publish postmortem", "Postmortem", "service-owner"),
      ],
    }
  } else if severity == 2 {
    {
      title: "SEV-2 customer-impacting response",
      steps: [
        required_step("Acknowledge alert", "Acknowledge", "on-call"),
        required_step("Diagnose impact", "Diagnose", "service-owner"),
        required_step("Mitigate customer impact", "Mitigate", "service-owner"),
        required_step("Verify recovery", "Verify", "observability"),
        optional_step("Publish postmortem", "Postmortem", "service-owner"),
      ],
    }
  } else {
    {
      title: "SEV-3 standard response",
      steps: [
        required_step("Acknowledge alert", "Acknowledge", "on-call"),
        required_step("Diagnose impact", "Diagnose", "service-owner"),
        required_step("Mitigate customer impact", "Mitigate", "service-owner"),
        optional_step("Verify recovery", "Verify", "observability"),
      ],
    }
  }
}

///|
/// Finds the first runbook step not represented by successful history.
pub fn next_runbook_step(
  runbook : IncidentRunbook,
  history : Array[@fsm.TransitionRecord[String, String]],
) -> RunbookStep? {
  for step in runbook.steps {
    let mut completed = false
    for record in history {
      if record.event == step.event {
        completed = true
      }
    }
    if !completed {
      return Some(step)
    }
  }
  None
}

///|
/// Counts completed required runbook steps.
pub fn completed_required_steps(
  runbook : IncidentRunbook,
  history : Array[@fsm.TransitionRecord[String, String]],
) -> Int {
  let mut completed = 0
  for step in runbook.steps {
    if !step.required {
      continue
    }
    for record in history {
      if record.event == step.event {
        completed += 1
        break
      }
    }
  }
  completed
}

///|
/// Returns a human-readable progress string for operator consoles.
pub fn runbook_progress(
  runbook : IncidentRunbook,
  history : Array[@fsm.TransitionRecord[String, String]],
) -> String {
  let completed = completed_required_steps(runbook, history)
  let mut total = 0
  for step in runbook.steps {
    if step.required {
      total += 1
    }
  }
  "\{runbook.title}: \{completed}/\{total} required steps"
}