///|
pub(all) enum Severity {
  Pass
  Warn
  Fail
} derive(Eq, Debug)

///|
pub(all) enum Region {
  NA
  EU
  APAC
  CN
  LATAM
  MEA
  OtherRegion
} derive(Eq, Debug)

///|
pub(all) enum UserTier {
  Free
  Pro
  Enterprise
  Staff
  Internal
} derive(Eq, Debug)

///|
pub(all) enum RolloutMode {
  Shadow
  DryRun
  Live
  KillSwitch
} derive(Eq, Debug)

///|
pub(all) enum GateDecision {
  Advance
  Hold
  Rollback
  Abort
} derive(Eq, Debug)

///|
pub(all) enum ValidationKind {
  PlanShape
  SegmentShape
  RiskBudgetShape
  MetricGate
  BlastRadiusGate
  ScheduleGate
  IdentityGate
} derive(Eq, Debug)

///|
pub(all) struct UserProfile {
  id : String
  region : Region
  tier : UserTier
  version : String
  tags : Array[String]
  staff : Bool
  traffic_units : Int
} derive(Eq, Debug)

///|
pub fn UserProfile::UserProfile(
  id? : String = "",
  region? : Region = OtherRegion,
  tier? : UserTier = Free,
  version? : String = "",
  tags? : Array[String] = [],
  staff? : Bool = false,
  traffic_units? : Int = 1,
) -> UserProfile {
  { id, region, tier, version, tags, staff, traffic_units }
}

///|
pub(all) struct SegmentRule {
  name : String
  include_regions : Array[Region]
  exclude_regions : Array[Region]
  include_tiers : Array[UserTier]
  exclude_tiers : Array[UserTier]
  require_tags : Array[String]
  exclude_tags : Array[String]
  min_version : String
  max_bucket_bp : Int
} derive(Eq, Debug)

///|
pub fn SegmentRule::SegmentRule(
  name? : String = "",
  include_regions? : Array[Region] = [],
  exclude_regions? : Array[Region] = [],
  include_tiers? : Array[UserTier] = [],
  exclude_tiers? : Array[UserTier] = [],
  require_tags? : Array[String] = [],
  exclude_tags? : Array[String] = [],
  min_version? : String = "",
  max_bucket_bp? : Int = 10000,
) -> SegmentRule {
  {
    name,
    include_regions,
    exclude_regions,
    include_tiers,
    exclude_tiers,
    require_tags,
    exclude_tags,
    min_version,
    max_bucket_bp,
  }
}

///|
pub(all) struct RolloutPhase {
  name : String
  start_minute : Int
  duration_minutes : Int
  percent_bp : Int
  mode : RolloutMode
  require_manual_approval : Bool
} derive(Eq, Debug)

///|
pub fn RolloutPhase::RolloutPhase(
  name? : String = "",
  start_minute? : Int = 0,
  duration_minutes? : Int = 60,
  percent_bp? : Int = 0,
  mode? : RolloutMode = Shadow,
  require_manual_approval? : Bool = false,
) -> RolloutPhase {
  {
    name,
    start_minute,
    duration_minutes,
    percent_bp,
    mode,
    require_manual_approval,
  }
}

///|
pub(all) struct RiskBudget {
  max_error_per_million : Int
  max_latency_p95_ms : Int
  min_samples : Int
  max_saturation_bp : Int
  max_blast_radius_bp : Int
  require_synthetic_pass : Bool
  max_dependency_failures : Int
} derive(Eq, Debug)

///|
pub fn RiskBudget::RiskBudget(
  max_error_per_million? : Int = 5000,
  max_latency_p95_ms? : Int = 800,
  min_samples? : Int = 100,
  max_saturation_bp? : Int = 8500,
  max_blast_radius_bp? : Int = 5000,
  require_synthetic_pass? : Bool = true,
  max_dependency_failures? : Int = 0,
) -> RiskBudget {
  {
    max_error_per_million,
    max_latency_p95_ms,
    min_samples,
    max_saturation_bp,
    max_blast_radius_bp,
    require_synthetic_pass,
    max_dependency_failures,
  }
}

///|
pub(all) struct MetricsSnapshot {
  minute : Int
  sample_count : Int
  error_per_million : Int
  latency_p95_ms : Int
  saturation_bp : Int
  synthetic_pass : Bool
  dependency_failures : Int
} derive(Eq, Debug)

///|
pub fn MetricsSnapshot::MetricsSnapshot(
  minute? : Int = 0,
  sample_count? : Int = 0,
  error_per_million? : Int = 0,
  latency_p95_ms? : Int = 0,
  saturation_bp? : Int = 0,
  synthetic_pass? : Bool = true,
  dependency_failures? : Int = 0,
) -> MetricsSnapshot {
  {
    minute,
    sample_count,
    error_per_million,
    latency_p95_ms,
    saturation_bp,
    synthetic_pass,
    dependency_failures,
  }
}

///|
pub(all) struct ExposureDecision {
  enabled : Bool
  bucket_bp : Int
  mode : RolloutMode
  phase_name : String
  reason : String
} derive(Eq, Debug)

///|
pub(all) struct GateResult {
  decision : GateDecision
  severity : Severity
  score : Int
  reasons : Array[String]
} derive(Eq, Debug)

///|
pub(all) struct BlastRadius {
  exposed_users : Int
  exposed_traffic_units : Int
  region_count : Int
  tier_count : Int
  percent_bp : Int
  risk_score : Int
} derive(Eq, Debug)

///|
pub(all) struct RolloutFinding {
  id : String
  kind : ValidationKind
  severity : Severity
  title : String
  detail : String
  repair : String
  evidence : String
  penalty : Int
} derive(Eq, Debug)

///|
pub(all) struct RolloutPlan {
  name : String
  salt : String
  segments : Array[SegmentRule]
  phases : Array[RolloutPhase]
  budget : RiskBudget
  owner : String
  repository : String
  package_name : String
} derive(Eq, Debug)

///|
pub fn RolloutPlan::RolloutPlan(
  name? : String = "",
  salt? : String = "",
  segments? : Array[SegmentRule] = [],
  phases? : Array[RolloutPhase] = [],
  budget? : RiskBudget = RiskBudget::RiskBudget(),
  owner? : String = "",
  repository? : String = "",
  package_name? : String = "",
) -> RolloutPlan {
  { name, salt, segments, phases, budget, owner, repository, package_name }
}

///|
pub(all) struct SimulationStep {
  minute : Int
  phase_name : String
  exposed_users : Int
  exposed_traffic_units : Int
  gate : GateResult
} derive(Eq, Debug)

///|
pub(all) struct SimulationReport {
  plan_name : String
  verdict : String
  score : Int
  findings : Array[RolloutFinding]
  steps : Array[SimulationStep]
  final_gate : GateResult
  blast_radius : BlastRadius
} derive(Eq, Debug)