///|
let env_filter_ws = " \t\r\n"

///|
pub(all) enum EnvFilterError {
  InvalidLevel(String)
  MalformedDirective(String)
} derive(Eq, Compare, Debug)

///|
pub fn EnvFilterError::to_string(self : EnvFilterError) -> String {
  match self {
    InvalidLevel(level) => "invalid env filter level: " + level
    MalformedDirective(directive) =>
      "malformed env filter directive: " + directive
  }
}

///|
pub impl Show for EnvFilterError with fn output(self, logger) {
  logger.write_string(self.to_string())
}

///|
pub(all) struct ParsedFilter {
  default_level : Level
  module_filters : Map[String, Level]
} derive(Debug)

///|
fn trim_env_filter_part(value : StringView) -> String {
  value.trim(chars=env_filter_ws).to_owned()
}

///|
fn parse_env_filter_level(level : String) -> Result[Level, EnvFilterError] {
  match Level::from_string(level) {
    Some(parsed) => Ok(parsed)
    None => Err(InvalidLevel(level))
  }
}

///|
/// Parse a compact filter directive string.
///
/// Supported directives are comma-separated bare levels (`info`) and exact
/// package filters (`brickfrog/moontrace=debug`). Empty directives are skipped,
/// duplicate defaults or package filters are accepted, and the last directive
/// wins. If no bare default is present, the parsed default is `Info`.
pub fn parse_env_filter(
  directive : String,
) -> Result[ParsedFilter, EnvFilterError] {
  let mut default_level = Info
  let filters : Map[String, Level] = {}
  for raw_part in directive.split(",") {
    let part = trim_env_filter_part(raw_part)
    if !part.is_empty() {
      match part.split_once("=") {
        Some((target_view, level_view)) => {
          let level_raw = level_view.to_owned()
          if level_raw.contains("=") {
            return Err(MalformedDirective(part))
          }
          let target = trim_env_filter_part(target_view)
          let level_text = trim_env_filter_part(level_view)
          if target.is_empty() || level_text.is_empty() {
            return Err(MalformedDirective(part))
          }
          match parse_env_filter_level(level_text) {
            Ok(level) => filters.set(target, level)
            Err(err) => return Err(err)
          }
        }
        None =>
          match parse_env_filter_level(part) {
            Ok(level) => default_level = level
            Err(err) => return Err(err)
          }
      }
    }
  }
  Ok({ default_level, module_filters: filters })
}

///|
/// Apply a parsed filter deterministically by replacing global filter state.
pub fn apply_env_filter(parsed : ParsedFilter) -> Unit {
  clear_module_filters()
  set_min_level(parsed.default_level)
  parsed.module_filters.each(fn(target, level) {
    set_module_filter(target, level)
  })
}

///|
pub fn ParsedFilter::apply(self : ParsedFilter) -> Unit {
  apply_env_filter(self)
}

///|
pub fn set_filter_from_directives(
  directive : String,
) -> Result[Unit, EnvFilterError] {
  match parse_env_filter(directive) {
    Ok(parsed) => {
      apply_env_filter(parsed)
      Ok(())
    }
    Err(err) => Err(err)
  }
}

///|
/// Initialize filters from `MOONTRACE_LOG` by default.
///
/// Unset or ASCII-whitespace-only values are no-ops. Present non-empty values
/// are parsed and applied, with invalid directives returned as structured
/// errors so logging is never widened by ignoring a bad filter.
pub fn initialize_from_env(
  env_var? : String = "MOONTRACE_LOG",
) -> Result[Unit, EnvFilterError] {
  match @env.get_env_var(env_var) {
    Some(value) =>
      if value.trim(chars=env_filter_ws).is_empty() {
        Ok(())
      } else {
        set_filter_from_directives(value)
      }
    None => Ok(())
  }
}