///|
fn asset_key(asset : @continuity_forge.AssetRef) -> String {
  match asset {
    @continuity_forge.AssetRef::Service(id) => "service:\{id.value}"
    @continuity_forge.AssetRef::Component(id) => "component:\{id.value}"
  }
}

///|
fn minutes(amount : Int) -> @continuity_forge.TimeSpan raise {
  @continuity_forge.TimeSpan::new(
    amount~,
    unit=@continuity_forge.TimeUnit::Minutes,
  )
}

///|
fn item(
  asset : @continuity_forge.AssetRef,
  level : @continuity_forge.ImpactLevel,
  duration : Int,
  resource : String,
) -> @continuity_forge.RecoveryItem raise {
  @continuity_forge.RecoveryItem::new(
    asset~,
    impact_level=level,
    recovery_time=minutes(duration),
    resource~,
  )
}

///|
fn main raise {
  let database = @continuity_forge.AssetRef::Component(
    @continuity_forge.ComponentId::new(value="postgres-primary"),
  )
  let api = @continuity_forge.AssetRef::Service(
    @continuity_forge.ServiceId::new(value="checkout-api"),
  )
  let worker = @continuity_forge.AssetRef::Service(
    @continuity_forge.ServiceId::new(value="checkout-worker"),
  )
  let router = @continuity_forge.AssetRef::Component(
    @continuity_forge.ComponentId::new(value="edge-router"),
  )
  let plan = @continuity_forge.plan_recovery(
    items=[
      item(worker, @continuity_forge.ImpactLevel::Medium, 15, "compute"),
      item(router, @continuity_forge.ImpactLevel::Low, 25, "network"),
      item(api, @continuity_forge.ImpactLevel::High, 20, "compute"),
      item(database, @continuity_forge.ImpactLevel::Critical, 10, "database"),
    ],
    dependencies=[
      @continuity_forge.define_dependency(dependent=api, dependency=database),
    ],
    constraints=@continuity_forge.RecoveryConstraints::new(
      target_window=minutes(45),
      available_resources=["database", "compute", "network"],
    ),
  )
  println("asset | resource | start | finish")
  for entry in plan.schedule {
    println(
      "\{asset_key(entry.item.asset)} | \{entry.item.resource} | \{entry.start_minutes} | \{entry.end_minutes}",
    )
  }
  println("dependency lower bound: \{plan.dependency_lower_bound_minutes}m")
  println("resource lower bound: \{plan.resource_lower_bound_minutes}m")
  println(
    "elapsed recovery window: \{plan.total_time_minutes}m / \{plan.target_window_minutes}m (slack \{plan.slack_minutes}m)",
  )
}