///|
pub(all) enum ActionKind {
  Acknowledge
  Reject
  Ignore
  Dispatch
  RetryLater
} derive(Eq, Debug)

///|
pub struct HandlerAction {
  kind : ActionKind
  handler : String
  reason : String
} derive(Eq, Debug)

///|
pub fn HandlerAction::new(
  kind : ActionKind,
  handler : String,
  reason : String,
) -> HandlerAction {
  { kind, handler, reason }
}

///|
pub struct HandlingPlan {
  actions : Array[HandlerAction]
  response : WebhookResponse
} derive(Eq, Debug)

///|
pub fn HandlingPlan::new(
  actions : Array[HandlerAction],
  response : WebhookResponse,
) -> HandlingPlan {
  { actions, response }
}

///|
pub fn plan_for_output(output : GuardPipelineOutput) -> HandlingPlan {
  if !output.verification.is_ok() {
    HandlingPlan::new(
      [HandlerAction::new(Reject, "", "verification failed")],
      response_for_output(output),
    )
  } else if !output.route.matched {
    HandlingPlan::new(
      [HandlerAction::new(Ignore, "", output.route.reason)],
      response_for_output(output),
    )
  } else {
    HandlingPlan::new(
      [
        HandlerAction::new(Acknowledge, "", "verified"),
        HandlerAction::new(Dispatch, output.route.handler, "route matched"),
      ],
      response_for_output(output),
    )
  }
}

///|
pub fn plan_text(plan : HandlingPlan) -> String {
  let builder = StringBuilder::new()
  for i in 0.. builder.write_string("ack")
      Reject => builder.write_string("reject")
      Ignore => builder.write_string("ignore")
      Dispatch => builder.write_string("dispatch")
      RetryLater => builder.write_string("retry")
    }
    builder.write_string(":")
    builder.write_string(plan.actions[i].handler)
    builder.write_string(":")
    builder.write_string(plan.actions[i].reason)
    builder.write_string("\n")
  }
  builder.write_string(response_text(plan.response))
  builder.to_string()
}

///|
pub fn plans_for_outputs(
  outputs : Array[GuardPipelineOutput],
) -> Array[HandlingPlan] {
  Array::makei(outputs.length(), i => plan_for_output(outputs[i]))
}