// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
fn build_long_index(
  globals : Array[Arg],
  args : Array[Arg],
) -> Map[String, Arg] {
  Map(
    [
      for arg in [..globals, ..args] if arg.info
      is (FlagInfo(long~, ..) | OptionInfo(long~, ..)) &&
      long is Some(name) => (name, arg)
    ],
  )
}

///|
fn build_short_index(globals : Array[Arg], args : Array[Arg]) -> Map[Char, Arg] {
  Map(
    [
      for arg in [..globals, ..args] if arg.info
      is (FlagInfo(short~, ..) | OptionInfo(short~, ..)) &&
      short is Some(value) => (value, arg)
    ],
  )
}

///|
fn collect_globals(args : Array[Arg]) -> Array[Arg] {
  args.filter(arg => arg.global && arg.info is (FlagInfo(_) | OptionInfo(_)))
}

///|
fn collect_non_global_names(args : Array[Arg]) -> @set.Set[String] {
  Set([ for arg in args if !arg.global => arg.name ])
}

///|
fn resolve_help_target(
  cmd : Command,
  argv : ArrayView[String],
  builtin_help_short : Bool,
  builtin_help_long : Bool,
  inherited_globals : Array[Arg],
  command_path : String,
) -> (Command, Array[Arg], String) raise ArgParseError {
  let targets = match argv {
    [.. pre, "-h"] if builtin_help_short => pre
    [.. pre, "--help"] if builtin_help_long => pre
    _ => argv
  }
  for
    name in targets
    current = cmd,
    current_path = command_path,
    current_globals = inherited_globals,
    subs = cmd.subcommands {
    if name.has_prefix("-") {
      raise InvalidArgument("unexpected help argument: \{name}")
    }
    guard subs.iter().find_first(sub => sub.name == name) is Some(sub) else {
      let message = if suggest_name(
          name,
          [
            for sub in subs if !sub.hidden => sub.name
          ],
        )
        is Some(best) {
        (
          $|unknown subcommand: \{name}
          $|
          $|  tip: a similar subcommand exists: '\{best}'
        )
      } else {
        "unknown subcommand: \{name}"
      }
      raise InvalidArgument(message)
    }
    let current_globals = merge_global_defs(
      current_globals,
      collect_globals(current.args),
    )
    let current_path = if current_path == "" {
      sub.name
    } else {
      "\{current_path} \{sub.name}"
    }
    continue sub, current_path, current_globals, sub.subcommands
  } nobreak {
    (current, current_globals, current_path)
  }
}

///|
fn split_long(arg : String) -> (StringView, String?) {
  let parts = [ for part in arg.split("=") => part ]
  if parts.length() <= 1 {
    let name = match parts[0].strip_prefix("--") {
      Some(view) => view
      None => parts[0]
    }
    (name, None)
  } else {
    let name = match parts[0].strip_prefix("--") {
      Some(view) => view
      None => parts[0]
    }
    let value = parts[1:].join("=")
    (name, Some(value))
  }
}