// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2026 clbbbb

///|
pub fn licenses(expr : Expr) -> Array[String] {
  match expr {
    License(id) => [id]
    LicenseWithException(id, _) => [id]
    And(left, right) => unique_strings(licenses(left) + licenses(right))
    Or(left, right) => unique_strings(licenses(left) + licenses(right))
  }
}

///|
pub fn exceptions(expr : Expr) -> Array[String] {
  match expr {
    License(_) => []
    LicenseWithException(_, ex) => [ex]
    And(left, right) => unique_strings(exceptions(left) + exceptions(right))
    Or(left, right) => unique_strings(exceptions(left) + exceptions(right))
  }
}

///|
pub fn operators(expr : Expr) -> Array[String] {
  match expr {
    License(_) => []
    LicenseWithException(_, _) => ["WITH"]
    And(left, right) =>
      unique_strings(["AND"] + operators(left) + operators(right))
    Or(left, right) =>
      unique_strings(["OR"] + operators(left) + operators(right))
  }
}

///|
pub fn depth(expr : Expr) -> Int {
  match expr {
    License(_) | LicenseWithException(_, _) => 1
    And(left, right) | Or(left, right) => 1 + max_int(depth(left), depth(right))
  }
}

///|
pub fn max_int(a : Int, b : Int) -> Int {
  if a > b {
    a
  } else {
    b
  }
}

///|
pub fn expression_stats(text : String) -> String {
  match parse(text).expr {
    Some(expr) =>
      "licenses=" +
      licenses(expr).length().to_string() +
      "\nexceptions=" +
      exceptions(expr).length().to_string() +
      "\noperators=" +
      operators(expr).length().to_string() +
      "\ndepth=" +
      depth(expr).to_string()
    None => "error"
  }
}

///|
pub fn contains_license(expr : Expr, id : String) -> Bool {
  contains_string(licenses(expr), canonical_license(id))
}

///|
pub fn contains_exception(expr : Expr, id : String) -> Bool {
  contains_string(exceptions(expr), canonical_exception(id))
}