// 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 suggest_long(name : StringView, long_index : Map[String, Arg]) -> String? {
  let candidates = long_index.keys().collect()
  if suggest_name(name, candidates) is Some(best) {
    Some("--\{best}")
  } else {
    None
  }
}

///|
fn suggest_short(short : Char, short_index : Map[Char, Arg]) -> String? {
  let candidates = short_index.keys().map(c => c.to_string()).collect()
  let input = short.to_string()
  if suggest_name(input, candidates) is Some(best) {
    Some("-\{best}")
  } else {
    None
  }
}

///|
/// Pick the candidate closest to `input` in UTF-16 code-unit Levenshtein
/// distance, keeping the first candidate on ties. The threshold is derived
/// from the input length in the same code units; candidates beyond it are
/// rejected by the banded search without computing their full distance.
fn suggest_name(input : StringView, candidates : Array[String]) -> String? {
  let max_dist = suggestion_threshold(input.length())
  for cand in candidates; best = (None : String?), best_dist = 0 {
    match
      @edit_distance.edit_distance_str_within(
        input,
        cand,
        max_distance=max_dist,
      ) {
      Some(dist) if best is None || dist < best_dist =>
        continue Some(cand), dist
      _ => continue best, best_dist
    }
  } nobreak {
    best
  }
}

///|
fn suggestion_threshold(len : Int) -> Int {
  if len <= 4 {
    1
  } else if len <= 8 {
    2
  } else {
    3
  }
}