///|
fn service_asset(
  value~ : String,
) -> @continuity_forge.AssetRef raise @continuity_forge.ModelError {
  @continuity_forge.AssetRef::Service(@continuity_forge.ServiceId::new(value~))
}

///|
fn component_asset(
  value~ : String,
) -> @continuity_forge.AssetRef raise @continuity_forge.ModelError {
  @continuity_forge.AssetRef::Component(
    @continuity_forge.ComponentId::new(value~),
  )
}

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

///|
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 main raise {
  let checkout_id = try! @continuity_forge.ServiceId::new(value="checkout-api")
  let database_id = try! @continuity_forge.ComponentId::new(
    value="postgres-primary",
  )
  let checkout = try! service_asset(value="checkout-api")
  let database = try! component_asset(value="postgres-primary")
  let dependency = try! @continuity_forge.define_dependency(
    dependent=checkout,
    dependency=database,
  )

  let _service = try! @continuity_forge.register_service(
    id=checkout_id,
    name="Checkout API",
    owner="Commerce platform",
  )
  let _component = try! @continuity_forge.register_component(
    id=database_id,
    name="Primary Postgres",
    technology="PostgreSQL",
  )
  let assets = [checkout, database]
  try! @continuity_forge.validate_dependencies(assets~, dependencies=[
    dependency,
  ])
  let order = try! @continuity_forge.order_dependencies(assets~, dependencies=[
    dependency,
  ])

  let bia = try! @continuity_forge.assess_business_impact(
    service_id=checkout_id,
    impact_score=85,
    rto=try! minutes(amount=30),
    rpo=try! minutes(amount=15),
    max_tolerable_downtime=try! minutes(amount=120),
  )
  let impact = try! @continuity_forge.simulate_impact(
    failed_asset=database,
    assets~,
    dependencies=[dependency],
  )

  let database_item = try! @continuity_forge.RecoveryItem::new(
    asset=database,
    impact_level=@continuity_forge.ImpactLevel::Critical,
    recovery_time=try! minutes(amount=10),
    resource="database-team",
  )
  let checkout_item = try! @continuity_forge.RecoveryItem::new(
    asset=checkout,
    impact_level=@continuity_forge.ImpactLevel::High,
    recovery_time=try! minutes(amount=20),
    resource="platform-team",
  )
  let recovery = try! @continuity_forge.plan_recovery(
    items=[checkout_item, database_item],
    dependencies=[dependency],
    constraints=try! @continuity_forge.RecoveryConstraints::new(
      target_window=try! minutes(amount=60),
      available_resources=["database-team", "platform-team"],
    ),
  )

  let restore_database = try! @continuity_forge.create_recovery_step(
    id="restore-db",
    asset=database,
    owner="database-team",
    requires_approval=false,
    prerequisites=[],
  )
  let restore_checkout = try! @continuity_forge.create_recovery_step(
    id="restore-api",
    asset=checkout,
    owner="platform-team",
    requires_approval=true,
    prerequisites=["restore-db"],
  )
  let playbook = try! @continuity_forge.create_playbook(
    id="checkout-recovery",
    steps=[restore_database, restore_checkout],
  )
  let drill = try! @continuity_forge.create_drill(
    id="checkout-drill",
    playbook~,
  )
  let drill = drill.start(actor="continuity-operator", timestamp_minutes=540)
  let drill = drill.begin_step(
    step_id="restore-db",
    actor="database-team",
    timestamp_minutes=544,
  )
  let drill = drill.complete_step(
    step_id="restore-db",
    actor="database-team",
    timestamp_minutes=552,
  )
  let drill = drill.begin_step(
    step_id="restore-api",
    actor="platform-team",
    timestamp_minutes=555,
  )
  let drill = drill.approve_step(
    step_id="restore-api",
    actor="resilience-approver",
    timestamp_minutes=557,
  )
  let drill = drill.complete_step(
    step_id="restore-api",
    actor="platform-team",
    timestamp_minutes=568,
  )
  let drill = drill.finish(actor="continuity-operator", timestamp_minutes=570)

  println("ContinuityForge minimal domain example")
  println("dependency order: \{order.map(asset_key).join(", ")}")
  println("BIA score: \{bia.impact_score}/100")
  println("affected assets: \{impact.affected.length()}")
  println(
    "recovery order: \{recovery.ordered.map(item => asset_key(item.asset)).join(", ")}",
  )
  println("recovery window: \{recovery.total_time_minutes} minutes")
  let drill_status = match drill.status {
    @continuity_forge.DrillStatus::Planned => "Planned"
    @continuity_forge.DrillStatus::Running => "Running"
    @continuity_forge.DrillStatus::Completed => "Completed"
  }
  println(
    "drill status: \{drill_status} (\{drill.audit_timeline().length()} events)",
  )
}