///|
struct ElkRenderCliArgs {
  show_help : Bool
  source : String?
  sweep_kernel : @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceSweepKernel
  trial_count_override : Int32?
  sweep_pass_count_override : Int32?
  trial_continuation_policy_override : @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceTrialContinuationPolicy?
  local_refinement_profile_override : @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceLocalRefinementProfile?
  trial_model_order_inversion_influence_override : Double?
  layout_engine : @model.LayoutEngine
}

///|
fn parse_positive_int(raw : String) -> Int32? {
  let value = @string.parse_int(raw.trim().to_owned()) catch {
    _ => return None
  }
  if value > 0 {
    Some(value)
  } else {
    None
  }
}

///|
fn parse_non_negative_double(raw : String) -> Double? {
  let value = @string.parse_double(raw.trim().to_owned()) catch {
    _ => return None
  }
  if value >= 0.0 {
    Some(value)
  } else {
    None
  }
}

///|
fn parse_sweep_kernel(
  raw : String,
) -> @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceSweepKernel? {
  let normalized = raw.trim().to_lower()
  if normalized == "default" {
    return Some(Default)
  }
  if normalized == "neighbor-mean" || normalized == "neighbor_mean" {
    return Some(NeighborMeanBidirectional)
  }
  if normalized == "neighbor-median" || normalized == "neighbor_median" {
    return Some(NeighborMedianBidirectional)
  }
  if normalized == "edge-slot" || normalized == "edge_slot" {
    return Some(NeighborMeanEdgeSlotBidirectional)
  }
  if normalized == "port-rank" || normalized == "port_rank" {
    return Some(NeighborMeanPortRankBidirectional)
  }
  None
}

///|
fn parse_trial_continuation_policy(
  raw : String,
) -> @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceTrialContinuationPolicy? {
  let normalized = raw.trim().to_lower()
  if normalized == "default" {
    return Some(DefaultTrialContinuationPolicy)
  }
  if normalized == "pass-changes" || normalized == "pass_changes" {
    return Some(WhilePassChanges)
  }
  if normalized == "objective-improves" || normalized == "objective_improves" {
    return Some(WhileObjectiveImproves)
  }
  None
}

///|
fn parse_local_refinement_profile(
  raw : String,
) -> @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceLocalRefinementProfile? {
  let normalized = raw.trim().to_lower()
  if normalized == "default" {
    return Some(DefaultLocalRefinementProfile)
  }
  if normalized == "none" {
    return Some(NoLocalRefinement)
  }
  if normalized == "adjacent-swap" || normalized == "adjacent_swap" {
    return Some(AdjacentSwapOnly)
  }
  if normalized == "rank-permutation" || normalized == "rank_permutation" {
    return Some(RankPermutationOnly)
  }
  if normalized == "adjacent-swap-then-rank-permutation" ||
    normalized == "adjacent_swap_then_rank_permutation" {
    return Some(AdjacentSwapThenRankPermutation)
  }
  None
}

///|
fn parse_layout_engine(raw : String) -> @model.LayoutEngine? {
  let normalized = raw.trim().to_lower()
  if normalized == "elk" {
    return Some(Elk)
  }
  if normalized == "elk-layered" || normalized == "elk_layered" {
    return Some(ElkLayered)
  }
  None
}

///|
fn parse_cli_args(args : Array[String]) -> ElkRenderCliArgs? {
  let mut show_help = false
  let mut source : String? = None
  let mut sweep_kernel : @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceSweepKernel = Default
  let mut trial_count_override : Int32? = None
  let mut sweep_pass_count_override : Int32? = None
  let mut trial_continuation_policy_override : @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceTrialContinuationPolicy? = None
  let mut local_refinement_profile_override : @layout_engine_graph_engine_elk_core.ElkLayeredRankTraceLocalRefinementProfile? = None
  let mut trial_model_order_inversion_influence_override : Double? = None
  let mut layout_engine : @model.LayoutEngine = Elk
  let mut expect_source = false
  let mut expect_sweep_kernel = false
  let mut expect_trial_count = false
  let mut expect_sweep_pass_count = false
  let mut expect_trial_continuation_policy = false
  let mut expect_local_refinement_profile = false
  let mut expect_layout_engine = false
  let mut expect_model_order_inversion_influence = false

  for arg in args {
    if expect_source {
      if arg is [.. "--", ..] {
        return None
      }
      source = Some(arg)
      expect_source = false
      continue
    }
    if expect_sweep_kernel {
      if arg is [.. "--", ..] {
        return None
      }
      match parse_sweep_kernel(arg) {
        Some(value) => sweep_kernel = value
        None => return None
      }
      expect_sweep_kernel = false
      continue
    }
    if expect_trial_count {
      if arg is [.. "--", ..] {
        return None
      }
      match parse_positive_int(arg) {
        Some(value) => trial_count_override = Some(value)
        None => return None
      }
      expect_trial_count = false
      continue
    }
    if expect_sweep_pass_count {
      if arg is [.. "--", ..] {
        return None
      }
      match parse_positive_int(arg) {
        Some(value) => sweep_pass_count_override = Some(value)
        None => return None
      }
      expect_sweep_pass_count = false
      continue
    }
    if expect_trial_continuation_policy {
      if arg is [.. "--", ..] {
        return None
      }
      match parse_trial_continuation_policy(arg) {
        Some(value) => trial_continuation_policy_override = Some(value)
        None => return None
      }
      expect_trial_continuation_policy = false
      continue
    }
    if expect_local_refinement_profile {
      if arg is [.. "--", ..] {
        return None
      }
      match parse_local_refinement_profile(arg) {
        Some(value) => local_refinement_profile_override = Some(value)
        None => return None
      }
      expect_local_refinement_profile = false
      continue
    }
    if expect_layout_engine {
      if arg is [.. "--", ..] {
        return None
      }
      match parse_layout_engine(arg) {
        Some(value) => layout_engine = value
        None => return None
      }
      expect_layout_engine = false
      continue
    }
    if expect_model_order_inversion_influence {
      if arg is [.. "--", ..] {
        return None
      }
      match parse_non_negative_double(arg) {
        Some(value) =>
          trial_model_order_inversion_influence_override = Some(value)
        None => return None
      }
      expect_model_order_inversion_influence = false
      continue
    }

    if arg == "--help" {
      show_help = true
      continue
    }
    if arg == "--source" {
      expect_source = true
      continue
    }
    if arg == "--sweep-kernel" {
      expect_sweep_kernel = true
      continue
    }
    if arg == "--trial-count" {
      expect_trial_count = true
      continue
    }
    if arg == "--sweep-pass-count" {
      expect_sweep_pass_count = true
      continue
    }
    if arg == "--trial-continuation-policy" {
      expect_trial_continuation_policy = true
      continue
    }
    if arg == "--local-refinement-profile" {
      expect_local_refinement_profile = true
      continue
    }
    if arg == "--layout-engine" {
      expect_layout_engine = true
      continue
    }
    if arg == "--model-order-inversion-influence" {
      expect_model_order_inversion_influence = true
      continue
    }

    if arg is [.. "--source=", .. raw_source] {
      let source_value = raw_source.to_owned()
      if source_value == "" {
        return None
      }
      source = Some(source_value)
      continue
    }
    if arg is [.. "--sweep-kernel=", .. raw_sweep_kernel] {
      match parse_sweep_kernel(raw_sweep_kernel.to_owned()) {
        Some(value) => sweep_kernel = value
        None => return None
      }
      continue
    }
    if arg is [.. "--trial-count=", .. raw_trial_count] {
      match parse_positive_int(raw_trial_count.to_owned()) {
        Some(value) => trial_count_override = Some(value)
        None => return None
      }
      continue
    }
    if arg is [.. "--sweep-pass-count=", .. raw_sweep_pass_count] {
      match parse_positive_int(raw_sweep_pass_count.to_owned()) {
        Some(value) => sweep_pass_count_override = Some(value)
        None => return None
      }
      continue
    }
    if arg
      is [.. "--trial-continuation-policy=", .. raw_trial_continuation_policy] {
      match
        parse_trial_continuation_policy(
          raw_trial_continuation_policy.to_owned(),
        ) {
        Some(value) => trial_continuation_policy_override = Some(value)
        None => return None
      }
      continue
    }
    if arg
      is [.. "--local-refinement-profile=", .. raw_local_refinement_profile] {
      match
        parse_local_refinement_profile(raw_local_refinement_profile.to_owned()) {
        Some(value) => local_refinement_profile_override = Some(value)
        None => return None
      }
      continue
    }
    if arg is [.. "--layout-engine=", .. raw_layout_engine] {
      match parse_layout_engine(raw_layout_engine.to_owned()) {
        Some(value) => layout_engine = value
        None => return None
      }
      continue
    }
    if arg
      is [
        .. "--model-order-inversion-influence=",
        .. raw_model_order_inversion_influence,
      ] {
      match
        parse_non_negative_double(
          raw_model_order_inversion_influence.to_owned(),
        ) {
        Some(value) =>
          trial_model_order_inversion_influence_override = Some(value)
        None => return None
      }
      continue
    }
    if arg is [.. "--", ..] {
      return None
    }
    if source is Some(_) {
      return None
    }
    source = Some(arg)
  }

  if expect_source ||
    expect_sweep_kernel ||
    expect_trial_count ||
    expect_sweep_pass_count ||
    expect_trial_continuation_policy ||
    expect_local_refinement_profile ||
    expect_layout_engine ||
    expect_model_order_inversion_influence {
    return None
  }
  Some({
    show_help,
    source,
    sweep_kernel,
    trial_count_override,
    sweep_pass_count_override,
    trial_continuation_policy_override,
    local_refinement_profile_override,
    trial_model_order_inversion_influence_override,
    layout_engine,
  })
}

///|
fn usage_text() -> String {
  (
    #|Usage:
    #|  moon run cmd/elk_render -- "graph TD\nA --> B"
    #|  moon run cmd/elk_render -- --trial-count=5 --sweep-pass-count=6 "graph TD\nA --> B"
    #|  moon run cmd/elk_render -- --layout-engine=elk-layered "graph TD\nA --> B"
    #|
    #|Flags:
    #|  --source           Mermaid source payload (or positional arg)
    #|  --sweep-kernel     default | neighbor-mean | neighbor-median | edge-slot | port-rank
    #|  --trial-count       Positive crossing trial-count override
    #|  --sweep-pass-count  Positive crossing sweep-pass-count override
    #|  --trial-continuation-policy  default | pass-changes | objective-improves
    #|  --local-refinement-profile  default | none | adjacent-swap | rank-permutation | adjacent-swap-then-rank-permutation
    #|  --model-order-inversion-influence  Non-negative trial tie-break influence
    #|  --layout-engine    elk | elk-layered
    #|  --help                   Show this usage text
  )
  .trim_end()
  .to_owned()
}

///|
fn cli_args_without_program() -> Array[String] {
  let all_args = @env.args()
  if all_args.length() <= 1 {
    []
  } else {
    let args : Array[String] = []
    for index in 1.. Unit {
  println(usage_text())
}

///|
fn print_svg_with_overrides(args : ElkRenderCliArgs) -> Unit {
  let source = match args.source {
    Some(value) => value
    None => {
      print_usage()
      return
    }
  }
  let graph = @parser_header_core.parse_mermaid(source) catch {
    err => {
      println("Error: \{err}")
      return
    }
  }
  let request : @layout_engine_graph_contract_core.GraphLayoutBackendRequest = {
    graph,
    options: {
      ..@model.RenderOptions::default(),
      layout_engine: Some(args.layout_engine),
    },
    use_subgraph_redirects: true,
    compact_fanin: false,
  }
  let backend = @layout_engine_graph_engine_elk_core.layout_graph_elk_backend_with_crossing_overrides(
    request,
    args.sweep_kernel,
    args.trial_count_override,
    args.sweep_pass_count_override,
    args.trial_continuation_policy_override,
    args.trial_model_order_inversion_influence_override,
    args.local_refinement_profile_override,
  )
  println(
    @renderer_svg.render_svg(
      backend.positioned_graph,
      @model.DiagramColors::default(),
      "Inter",
      false,
    ),
  )
}

///|
fn run() -> Unit {
  let args = cli_args_without_program()
  match parse_cli_args(args) {
    Some(parsed) =>
      if parsed.show_help {
        print_usage()
      } else {
        print_svg_with_overrides(parsed)
      }
    None => print_usage()
  }
}

///|
fn main {
  run()
}