///|
/// Named demonstration scenarios distributed with the package.
pub(all) enum DemoScenario {
  CommunityCare
  CampusVolunteers
  SuddenAbsence
} derive(Debug, Eq)

///|
/// Parse a scenario name accepted by the CLI.
pub fn parse_demo_scenario(name : String) -> DemoScenario? {
  match name.to_lower() {
    "community" | "community-care" | "care" => Some(CommunityCare)
    "campus" | "campus-volunteers" | "volunteers" => Some(CampusVolunteers)
    "absence" | "sudden-absence" | "reschedule" => Some(SuddenAbsence)
    _ => None
  }
}

///|
/// Stable name for a demonstration scenario.
pub fn demo_scenario_name(value : DemoScenario) -> String {
  match value {
    CommunityCare => "community-care"
    CampusVolunteers => "campus-volunteers"
    SuddenAbsence => "sudden-absence"
  }
}

///|
fn demo_place(id : String, x : Int, y : Int, zone : String) -> Location {
  location(id, x, y, zone)
}

///|
fn demo_worker(
  id : String,
  name : String,
  kind : WorkerKind,
  home : Location,
  skills : Array[Skill],
  availability : Array[TimeWindow],
) -> Worker {
  {
    ..worker(id, name, kind, home),
    skills,
    availability,
    max_minutes: 360,
    max_visits: 6,
    min_break_minutes: 10,
  }
}

///|
fn community_workers() -> Array[Worker] {
  [
    demo_worker(
      "w-lin",
      "Lin",
      CareWorker,
      demo_place("lin-home", 0, 0, "central"),
      [skill("companionship", 3), skill("meal", 2), skill("mobility", 2)],
      [time_window(480, 1020)],
    ),
    demo_worker(
      "w-chen",
      "Chen",
      Volunteer,
      demo_place("chen-home", 6, 1, "east"),
      [skill("companionship", 2), skill("shopping", 3), skill("digital", 2)],
      [time_window(540, 1080)],
    ),
    demo_worker(
      "w-zhao",
      "Zhao",
      Volunteer,
      demo_place("zhao-home", -3, 2, "west"),
      [skill("companionship", 2), skill("meal", 1), skill("driving", 2)],
      [time_window(480, 840), time_window(900, 1140)],
    ),
  ]
}

///|
fn community_visits() -> Array[Visit] {
  [
    {
      ..visit(
        "visit-breakfast",
        "resident-a",
        "Breakfast preparation",
        demo_place("resident-a", 1, 0, "central"),
        time_window(510, 630),
        45,
      ),
      required_skills: [skill("meal", 1)],
      priority: High,
      continuity_group: Some("resident-a"),
    },
    {
      ..visit(
        "visit-walk",
        "resident-a",
        "Mobility walk",
        demo_place("resident-a", 1, 0, "central"),
        time_window(660, 840),
        60,
      ),
      required_skills: [skill("mobility", 2)],
      priority: Normal,
      preferred_worker_ids: ["w-lin"],
      continuity_group: Some("resident-a"),
    },
    {
      ..visit(
        "visit-shopping",
        "resident-b",
        "Grocery shopping",
        demo_place("market-east", 7, 2, "east"),
        time_window(600, 900),
        75,
      ),
      required_skills: [skill("shopping", 2)],
      priority: Normal,
      preferred_worker_ids: ["w-chen"],
    },
    {
      ..visit(
        "visit-video-call",
        "resident-c",
        "Family video call setup",
        demo_place("resident-c", 5, 0, "east"),
        time_window(840, 1020),
        45,
      ),
      required_skills: [skill("digital", 1)],
      priority: Low,
      required: false,
    },
    {
      ..visit(
        "visit-clinic",
        "resident-d",
        "Clinic transport accompaniment",
        demo_place("clinic-west", -5, 2, "west"),
        time_window(900, 1080),
        90,
      ),
      required_skills: [skill("driving", 2), skill("companionship", 1)],
      priority: Critical,
      preferred_worker_ids: ["w-zhao"],
    },
  ]
}

///|
fn campus_workers() -> Array[Worker] {
  [
    demo_worker(
      "student-a",
      "Student A",
      Volunteer,
      demo_place("dorm-a", 0, 0, "north-campus"),
      [skill("registration", 2), skill("guidance", 1)],
      [time_window(480, 780)],
    ),
    demo_worker(
      "student-b",
      "Student B",
      Volunteer,
      demo_place("dorm-b", 3, 1, "north-campus"),
      [skill("registration", 1), skill("first_aid", 2)],
      [time_window(480, 900)],
    ),
    demo_worker(
      "student-c",
      "Student C",
      Volunteer,
      demo_place("dorm-c", 8, 0, "south-campus"),
      [skill("guidance", 3), skill("logistics", 2)],
      [time_window(540, 960)],
    ),
  ]
}

///|
fn campus_visits() -> Array[Visit] {
  [
    {
      ..visit(
        "campus-registration",
        "event-office",
        "Registration desk",
        demo_place("hall", 2, 1, "north-campus"),
        time_window(510, 630),
        90,
      ),
      required_skills: [skill("registration", 2)],
      priority: Critical,
    },
    {
      ..visit(
        "campus-guide-a",
        "visitor-group-a",
        "Campus guidance",
        demo_place("gate", 5, 0, "central-campus"),
        time_window(600, 780),
        60,
      ),
      required_skills: [skill("guidance", 1)],
      priority: High,
    },
    {
      ..visit(
        "campus-first-aid",
        "event-office",
        "First aid post",
        demo_place("sports-field", 9, 1, "south-campus"),
        time_window(660, 900),
        120,
      ),
      required_skills: [skill("first_aid", 2)],
      priority: Critical,
    },
    {
      ..visit(
        "campus-logistics",
        "event-office",
        "Material delivery",
        demo_place("warehouse", 10, 2, "south-campus"),
        time_window(540, 840),
        75,
      ),
      required_skills: [skill("logistics", 2)],
      priority: Normal,
    },
  ]
}

///|
/// Build a complete request for a named scenario.
pub fn demo_request(scenario : DemoScenario) -> ScheduleRequest {
  match scenario {
    CommunityCare | SuddenAbsence =>
      schedule_request(community_workers(), community_visits())
    CampusVolunteers => schedule_request(campus_workers(), campus_visits())
  }
}

///|
/// Solve one built-in demonstration.
pub fn run_demo(scenario : DemoScenario) -> Schedule {
  solve(demo_request(scenario))
}

///|
/// Run the absence demonstration and return its impact report.
pub fn run_absence_demo() -> RescheduleReport {
  let request = demo_request(SuddenAbsence)
  let baseline = solve(request)
  reschedule(baseline, request, [
    WorkerAbsent(worker_id="w-lin", from_minute=480, to_minute=1140),
  ])
}