///|
/// Normalize common aliases to SPDX identifiers.
pub fn normalize_license(identifier : StringView) -> String {
  match identifier.trim().to_upper() {
    "APACHE 2" | "APACHE-2" | "APACHE2" | "APACHE-2.0" => "Apache-2.0"
    "MIT" | "MIT LICENSE" => "MIT"
    "BSD-2" | "BSD 2-CLAUSE" | "BSD-2-CLAUSE" => "BSD-2-Clause"
    "BSD-3" | "BSD 3-CLAUSE" | "BSD-3-CLAUSE" => "BSD-3-Clause"
    "MPL-2" | "MPL-2.0" => "MPL-2.0"
    "GPL-2" | "GPL-2.0" | "GPL-2.0-ONLY" => "GPL-2.0-only"
    "GPL-2.0+" | "GPL-2.0-OR-LATER" => "GPL-2.0-or-later"
    "GPL-3" | "GPL-3.0" | "GPL-3.0-ONLY" => "GPL-3.0-only"
    "GPL-3.0+" | "GPL-3.0-OR-LATER" => "GPL-3.0-or-later"
    "LGPL-2.1" | "LGPL-2.1-ONLY" => "LGPL-2.1-only"
    "LGPL-2.1+" | "LGPL-2.1-OR-LATER" => "LGPL-2.1-or-later"
    "LGPL-3" | "LGPL-3.0" | "LGPL-3.0-ONLY" => "LGPL-3.0-only"
    "LGPL-3.0+" | "LGPL-3.0-OR-LATER" => "LGPL-3.0-or-later"
    "AGPL-3" | "AGPL-3.0" | "AGPL-3.0-ONLY" => "AGPL-3.0-only"
    "AGPL-3.0+" | "AGPL-3.0-OR-LATER" => "AGPL-3.0-or-later"
    "EPL-2" | "EPL-2.0" => "EPL-2.0"
    "EUPL-1.2" => "EUPL-1.2"
    "ISC" => "ISC"
    "ZLIB" => "Zlib"
    "UNLICENSE" => "Unlicense"
    value => value.to_owned()
  }
}

///|
fn is_known_spdx_atom(identifier : StringView) -> Bool {
  match normalize_license(identifier) {
    "Apache-2.0"
    | "MIT"
    | "BSD-2-Clause"
    | "BSD-3-Clause"
    | "MPL-2.0"
    | "GPL-2.0-only"
    | "GPL-2.0-or-later"
    | "GPL-3.0-only"
    | "GPL-3.0-or-later"
    | "LGPL-2.1-only"
    | "LGPL-2.1-or-later"
    | "LGPL-3.0-only"
    | "LGPL-3.0-or-later"
    | "AGPL-3.0-only"
    | "AGPL-3.0-or-later"
    | "EPL-2.0"
    | "EUPL-1.2"
    | "ISC"
    | "Zlib"
    | "Unlicense"
    | "CC0-1.0"
    | "BSL-1.0" => true
    _ => false
  }
}

///|
fn is_known_spdx_exception(identifier : StringView) -> Bool {
  match identifier.trim() {
    "Classpath-exception-2.0"
    | "LLVM-exception"
    | "Autoconf-exception-3.0"
    | "GCC-exception-3.1" => true
    _ => false
  }
}

///|
fn strip_parens(value : StringView) -> StringView {
  let value = value.trim()
  if value.has_prefix("(") && value.has_suffix(")") && value.length() >= 2 {
    value[1:value.length() - 1].trim()
  } else {
    value
  }
}

///|
/// Validate a practical subset of SPDX expressions: identifiers joined by
/// `AND` or `OR`, with optional grouping parentheses.
pub fn valid_spdx(expression : StringView) -> Bool {
  let expression = strip_parens(expression)
  guard !expression.is_empty() else { return false }
  if expression.contains(" AND ") {
    for part in expression.split(" AND ") {
      guard valid_spdx(part) else { return false }
    }
    return true
  }
  if expression.contains(" OR ") {
    for part in expression.split(" OR ") {
      guard valid_spdx(part) else { return false }
    }
    return true
  }
  match expression.split_once(" WITH ") {
    Some((license, exception)) =>
      return is_known_spdx_atom(license) && is_known_spdx_exception(exception)
    None => ()
  }
  is_known_spdx_atom(expression)
}

///|
/// Identify common license texts without relying on file names.
pub fn detect_license(text : StringView) -> String? {
  let upper = text.to_upper()
  if upper.contains("APACHE LICENSE") &&
    upper.contains("VERSION 2.0, JANUARY 2004") {
    Some("Apache-2.0")
  } else if upper.contains("PERMISSION IS HEREBY GRANTED, FREE OF CHARGE") &&
    upper.contains("THE SOFTWARE IS PROVIDED \"AS IS\"") {
    Some("MIT")
  } else if upper.contains("MOZILLA PUBLIC LICENSE") &&
    upper.contains("VERSION 2.0") {
    Some("MPL-2.0")
  } else if upper.contains("ECLIPSE PUBLIC LICENSE") &&
    (upper.contains("VERSION 2.0") || upper.contains("- V 2.0")) {
    Some("EPL-2.0")
  } else if upper.contains("GNU AFFERO GENERAL PUBLIC LICENSE") &&
    upper.contains("VERSION 3") {
    Some("AGPL-3.0-only")
  } else if upper.contains("GNU GENERAL PUBLIC LICENSE") &&
    upper.contains("VERSION 3") {
    Some("GPL-3.0-only")
  } else if upper.contains("GNU GENERAL PUBLIC LICENSE") &&
    upper.contains("VERSION 2") {
    Some("GPL-2.0-only")
  } else if upper.contains("REDISTRIBUTION AND USE IN SOURCE AND BINARY FORMS") &&
    upper.contains("NEITHER THE NAME") {
    Some("BSD-3-Clause")
  } else if upper.contains("REDISTRIBUTION AND USE IN SOURCE AND BINARY FORMS") {
    Some("BSD-2-Clause")
  } else if upper.contains("ISC LICENSE") ||
    (
      upper.contains("PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE") &&
      upper.contains("THE SOFTWARE IS PROVIDED \"AS IS\"")
    ) {
    Some("ISC")
  } else if upper.contains("THIS SOFTWARE IS PROVIDED 'AS-IS'") &&
    upper.contains("ALTERED SOURCE VERSIONS MUST BE PLAINLY MARKED") {
    Some("Zlib")
  } else if upper.contains("CC0 1.0 UNIVERSAL") &&
    upper.contains("PUBLIC DOMAIN") {
    Some("CC0-1.0")
  } else {
    None
  }
}