///|
struct OrderContext {
  amount : Int
  packages : Int
  refunds : Int
}

///|
fn order_builder() -> @fsm.Builder[String, String, OrderContext] {
  @fsm.Builder::new()
  .transition_do("Created", "Pay", "Paid", fn(
    _s : String,
    _e : String,
    ctx : OrderContext,
  ) {
    { amount: ctx.amount, packages: ctx.packages, refunds: ctx.refunds }
  })
  .transition_do("Paid", "Pack", "Packed", fn(
    _s : String,
    _e : String,
    ctx : OrderContext,
  ) {
    { amount: ctx.amount, packages: ctx.packages + 1, refunds: ctx.refunds }
  })
  .transition_if_do(
    "Packed",
    "Ship",
    "Shipped",
    fn(_s : String, _e : String, ctx : OrderContext) { ctx.packages > 0 },
    fn(_s : String, _e : String, ctx : OrderContext) {
      { amount: ctx.amount, packages: ctx.packages, refunds: ctx.refunds }
    },
  )
  .transition("Shipped", "Deliver", "Delivered")
  .transition("Paid", "Cancel", "Cancelled")
  .transition("Packed", "Cancel", "Cancelled")
  .transition_do("Shipped", "Return", "Returned", fn(
    _s : String,
    _e : String,
    ctx : OrderContext,
  ) {
    { amount: ctx.amount, packages: ctx.packages, refunds: ctx.refunds + 1 }
  })
  .on_exit("Paid", fn(_s : String, event : String, _ctx : OrderContext) {
    println("Leaving Paid after \{event}")
  })
  .on_enter("Delivered", fn(_s : String, _event : String, ctx : OrderContext) {
    println("Delivered amount=\{ctx.amount}")
  })
}

///|
fn print_report(label : String, report : @fsm.BatchReport[String]) -> Unit {
  println(
    "\{label}: successful=\{report.successful}, rejected=\{report.rejected}, complete=\{report.complete}",
  )
  for outcome in report.outcomes {
    match outcome.error {
      Some(err) =>
        println(
          "  \{outcome.event}: rejected (\{@fsm.format_transition_error(err)})",
        )
      None => println("  \{outcome.event}: accepted")
    }
  }
}

///|
fn main {
  println("--- Order Workflow Example ---")
  let builder = order_builder()

  let normal = builder.build("Created", { amount: 299, packages: 0, refunds: 0 })
  let normal_report = normal.try_send_all(["Pay", "Pack", "Ship", "Deliver"])
  print_report("Normal flow", normal_report)
  println("Final state: \{normal.state()}")
  println("History length: \{normal.history().length()}")
  println("Audit entries: \{normal.audit_log().length()}")
  println("Successful events: \{normal.metrics().successful}")

  let compensating = builder.build("Created", {
    amount: 299,
    packages: 0,
    refunds: 0,
  })
  ignore(compensating.try_send_all(["Pay", "Pack", "Ship"]))
  let checkpoint = compensating.checkpoint()
  let rollback_report = compensating.try_send_all(["Return", "Deliver"])
  print_report("Return batch", rollback_report)
  if !rollback_report.complete {
    compensating.restore(checkpoint)
  }
  println("Compensated state: \{compensating.state()}")
  println("Compensated refunds: \{compensating.context().refunds}")
  println("Compensated history: \{compensating.history().length()}")
  println("Mermaid Diagram:\n" + @fsm.to_mermaid(builder))
}