///|
/// Public metadata for the built-in examples and regression fixtures.
pub struct CatalogEntry {
  name : String
  variant : @core.ProblemVariant
  customers : Int
  source : String
  factory : () -> @core.VrpInstance
}

///|
pub fn CatalogEntry::name(self : CatalogEntry) -> String {
  self.name
}

///|
pub fn CatalogEntry::variant(self : CatalogEntry) -> @core.ProblemVariant {
  self.variant
}

///|
pub fn CatalogEntry::customer_count(self : CatalogEntry) -> Int {
  self.customers
}

///|
pub fn CatalogEntry::source(self : CatalogEntry) -> String {
  self.source
}

///|
pub fn CatalogEntry::load(self : CatalogEntry) -> @core.VrpInstance {
  (self.factory)()
}

///|
pub fn sample_catalog() -> Array[CatalogEntry] {
  [
    {
      name: "small-cvrp",
      variant: @core.ProblemVariant::CVRP,
      customers: 8,
      source: "synthetic teaching fixture",
      factory: small_cvrp_sample,
    },
    {
      name: "urban-vrptw",
      variant: @core.ProblemVariant::VRPTW,
      customers: 10,
      source: "synthetic teaching fixture",
      factory: urban_vrptw_sample,
    },
    {
      name: "balanced-dispatch",
      variant: @core.ProblemVariant::VRPTW,
      customers: 12,
      source: "synthetic teaching fixture",
      factory: balanced_dispatch_sample,
    },
    {
      name: "micro-cvrp",
      variant: @core.ProblemVariant::CVRP,
      customers: 3,
      source: "synthetic edge-case fixture",
      factory: micro_cvrp_sample,
    },
    {
      name: "tight-vrptw",
      variant: @core.ProblemVariant::VRPTW,
      customers: 6,
      source: "synthetic edge-case fixture",
      factory: tight_vrptw_sample,
    },
    {
      name: "infeasible-capacity",
      variant: @core.ProblemVariant::CVRP,
      customers: 2,
      source: "synthetic negative-path fixture",
      factory: infeasible_capacity_sample,
    },
    {
      name: "generated-stress",
      variant: @core.ProblemVariant::CVRP,
      customers: 48,
      source: "seeded deterministic generator",
      factory: generated_stress_sample,
    },
  ]
}

///|
pub fn catalog_find(name : String) -> CatalogEntry? {
  for entry in sample_catalog() {
    if entry.name == name {
      return Some(entry)
    }
  }
  None
}

///|
pub fn catalog_names() -> Array[String] {
  sample_catalog().map(fn(entry) { entry.name })
}

///|
pub fn catalog_variant_count(variant : @core.ProblemVariant) -> Int {
  sample_catalog().count_if(fn(entry) { entry.variant == variant })
}

///|
pub fn catalog_customer_total() -> Int {
  sample_catalog().fold(init=0, fn(total, entry) { total + entry.customers })
}

///|
pub fn catalog_overview() -> String {
  [
    "samples=\{sample_catalog().length()}",
    "cvrp=\{catalog_variant_count(@core.ProblemVariant::CVRP)}",
    "vrptw=\{catalog_variant_count(@core.ProblemVariant::VRPTW)}",
    "customers=\{catalog_customer_total()}",
  ].join(" ")
}