///|
pub let moon_fwd_provider_failed_retry : String = "FWD-001"

///|
pub let moon_fwd_all_providers_failed : String = "FWD-002"

///|
pub let moon_fwd_single_provider_failed : String = "FWD-003"

///|
pub enum MoonProxyError {
  AlreadyRunning
  NotRunning
  UpstreamError(status~ : Int, body~ : String?)
  Timeout(String)
  StreamIdleTimeout(Int)
  ForwardFailed(String)
  NoAvailableProvider
  AllProvidersCircuitOpenError
  NoProvidersConfiguredError
  MaxRetriesExceeded
  ProviderUnhealthy(String)
  ConfigError(String)
  InvalidRequest(String)
  AuthError(String)
  DatabaseError(String)
  TransformError(String)
  Unknown(String)
}

///|
pub fn MoonProxyError::to_string(self : MoonProxyError) -> String {
  match self {
    AlreadyRunning => "proxy already running"
    NotRunning => "proxy not running"
    UpstreamError(status~, body~) =>
      match body {
        Some(body) => "upstream error \{status}: \{body}"
        None => "upstream error \{status}"
      }
    Timeout(message) => "timeout: \{message}"
    StreamIdleTimeout(seconds) => "stream idle timeout after \{seconds}s"
    ForwardFailed(message) => "forward failed: \{message}"
    NoAvailableProvider => "no available provider"
    AllProvidersCircuitOpenError => "all providers circuit open"
    NoProvidersConfiguredError => "no providers configured"
    MaxRetriesExceeded => "max retries exceeded"
    ProviderUnhealthy(message) => "provider unhealthy: \{message}"
    ConfigError(message) => "config error: \{message}"
    InvalidRequest(message) => "invalid request: \{message}"
    AuthError(message) => "auth error: \{message}"
    DatabaseError(message) => "database error: \{message}"
    TransformError(message) => "transform error: \{message}"
    Unknown(message) => message
  }
}

///|
pub fn moon_map_proxy_error_to_status(error : MoonProxyError) -> Int {
  match error {
    AlreadyRunning => @status.Conflict
    NotRunning => @status.ServiceUnavailable
    UpstreamError(status~, ..) => status
    Timeout(_) | StreamIdleTimeout(_) => @status.GatewayTimeout
    ForwardFailed(_) => @status.BadGateway
    NoAvailableProvider
    | AllProvidersCircuitOpenError
    | NoProvidersConfiguredError
    | MaxRetriesExceeded
    | ProviderUnhealthy(_) => @status.ServiceUnavailable
    ConfigError(_) | InvalidRequest(_) => @status.BadRequest
    AuthError(_) => @status.Unauthorized
    DatabaseError(_) => @status.InternalServerError
    TransformError(_) => @status.UnprocessableEntity
    Unknown(_) => @status.InternalServerError
  }
}

///|
pub fn moon_proxy_error_message(error : MoonProxyError) -> String {
  match error {
    UpstreamError(status~, body~) =>
      match body {
        Some(body) => "上游错误 (\{status}): \{body}"
        None => "上游错误 (\{status})"
      }
    Timeout(message) => "请求超时: \{message}"
    ForwardFailed(message) => "转发失败: \{message}"
    NoAvailableProvider => "无可用 Provider"
    AllProvidersCircuitOpenError => "所有供应商已熔断,无可用渠道"
    NoProvidersConfiguredError => "未配置供应商"
    MaxRetriesExceeded => "所有 Provider 都失败,重试耗尽"
    ProviderUnhealthy(message) => "Provider 不健康: \{message}"
    DatabaseError(message) => "数据库错误: \{message}"
    TransformError(message) => "请求/响应转换错误: \{message}"
    _ => error.to_string()
  }
}

///|
fn moon_proxy_error_diagnostic_variants() -> Array[MoonProxyError] {
  [
    AlreadyRunning,
    NotRunning,
    UpstreamError(status=502, body=Some("upstream")),
    Timeout("timeout"),
    StreamIdleTimeout(30),
    ForwardFailed("forward failed"),
    NoAvailableProvider,
    AllProvidersCircuitOpenError,
    NoProvidersConfiguredError,
    MaxRetriesExceeded,
    ProviderUnhealthy("provider"),
    ConfigError("config"),
    InvalidRequest("request"),
    AuthError("auth"),
    DatabaseError("database"),
    TransformError("transform"),
    Unknown("unknown"),
  ]
}

///|
fn moon_build_retryable_failure_log(
  provider_name : String,
  attempted_providers : Int,
  total_providers : Int,
  error : MoonProxyError,
) -> (String, String) {
  let error_summary = moon_summarize_proxy_error(error)
  if total_providers <= 1 {
    (
      moon_fwd_single_provider_failed,
      "Provider \{provider_name} 请求失败: \{error_summary}",
    )
  } else {
    (
      moon_fwd_provider_failed_retry,
      "Provider \{provider_name} 失败,继续尝试下一个 (\{attempted_providers}/\{total_providers}): \{error_summary}",
    )
  }
}

///|
fn moon_build_terminal_failure_log(
  attempted_providers : Int,
  total_providers : Int,
  last_error : MoonProxyError?,
) -> (String, String)? {
  if total_providers <= 1 {
    return None
  }
  let error_summary = match last_error {
    Some(error) => moon_summarize_proxy_error(error)
    None => "未知错误"
  }
  Some(
    (
      moon_fwd_all_providers_failed,
      "已尝试 \{attempted_providers}/\{total_providers} 个 Provider,均失败。最后错误: \{error_summary}",
    ),
  )
}

///|
fn init {
  ignore(moon_proxy_error_diagnostic_variants())
  ignore(
    moon_build_retryable_failure_log(
      "provider",
      1,
      2,
      ForwardFailed("forward failed"),
    ),
  )
  ignore(moon_build_terminal_failure_log(2, 2, Some(Timeout("timeout"))))
}

///|
fn moon_summarize_proxy_error(error : MoonProxyError) -> String {
  match error {
    UpstreamError(status~, body~) =>
      match body {
        Some(body) => {
          let summary = moon_summarize_upstream_body(body)
          if summary.is_empty() {
            "上游 HTTP \{status}"
          } else {
            "上游 HTTP \{status}: \{summary}"
          }
        }
        None => "上游 HTTP \{status}"
      }
    Timeout(message) =>
      "请求超时: \{moon_summarize_text_for_log(message, 180)}"
    ForwardFailed(message) =>
      "请求转发失败: \{moon_summarize_text_for_log(message, 180)}"
    TransformError(message) =>
      "响应转换失败: \{moon_summarize_text_for_log(message, 180)}"
    ConfigError(message) =>
      "配置错误: \{moon_summarize_text_for_log(message, 180)}"
    AuthError(message) =>
      "认证失败: \{moon_summarize_text_for_log(message, 180)}"
    _ => moon_summarize_text_for_log(error.to_string(), 180)
  }
}

///|
fn moon_summarize_upstream_body(body : String) -> String {
  let json_body = @json.parse(body) catch {
    _ => return moon_summarize_text_for_log(body, 180)
  }
  match moon_json_error_message(json_body) {
    Some(message) => moon_summarize_text_for_log(message, 180)
    None => moon_summarize_text_for_log(json_body.stringify(), 180)
  }
}

///|
fn moon_json_error_message(body : Json) -> String? {
  match body {
    Object(obj) => {
      match obj.get("error") {
        Some(Object(error_obj)) =>
          match json_string_from_map(error_obj, "message") {
            Some(message) => return Some(message)
            None => ()
          }
        Some(String(message)) => return Some(message)
        _ => ()
      }
      match json_string_from_map(obj, "message") {
        Some(message) => return Some(message)
        None => ()
      }
      match json_string_from_map(obj, "detail") {
        Some(message) => return Some(message)
        None => ()
      }
      None
    }
    _ => None
  }
}

///|
fn moon_summarize_text_for_log(text : String, max_chars : Int) -> String {
  let normalized = moon_collapse_ascii_whitespace(text).trim()
  if normalized.length() <= max_chars {
    normalized.to_owned()
  } else {
    normalized[:max_chars].trim().to_owned() + "..."
  }
}

///|
fn moon_collapse_ascii_whitespace(text : String) -> String {
  let buffer = StringBuilder::new()
  let mut in_whitespace = false
  let mut has_output = false
  for ch in text {
    if moon_is_ascii_whitespace(ch) {
      in_whitespace = true
    } else {
      if in_whitespace && has_output {
        buffer.write_char(' ')
      }
      buffer.write_char(ch)
      has_output = true
      in_whitespace = false
    }
  }
  buffer.to_string()
}

///|
fn moon_is_ascii_whitespace(ch : Char) -> Bool {
  ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'
}