use std::sync::OnceLock;

use super::*;

pub async fn send_alert(
  url: &str,
  email: Option<&str>,
  alert: &Alert,
) -> anyhow::Result<()> {
  let content = standard_alert_content(alert);
  if content.is_empty() {
    return Ok(());
  }

  let VariablesAndSecrets { variables, secrets } =
    get_variables_and_secrets().await?;
  let mut url_interpolated = url.to_string();

  let mut interpolator =
    Interpolator::new(Some(&variables), &secrets);

  interpolator.interpolate_string(&mut url_interpolated)?;

  send_message(&url_interpolated, email, content)
    .await
    .map_err(|e| {
      let replacers = interpolator
        .secret_replacers
        .into_iter()
        .collect::<Vec<_>>();
      let sanitized_error =
        svi::replace_in_string(&format!("{e:?}"), &replacers);
      anyhow::Error::msg(format!(
        "Error with request to Ntfy: {sanitized_error}"
      ))
    })
}

async fn send_message(
  url: &str,
  email: Option<&str>,
  content: String,
) -> anyhow::Result<()> {
  let mut request = http_client()
    .post(url)
    .header("Title", "Komodo Alert")
    .body(content);

  if let Some(email) = email {
    request = request.header("X-Email", email);
  }

  let response =
    request.send().await.context("Failed to send message")?;

  let status = response.status();
  if status.is_success() {
    debug!("ntfy alert sent successfully: {}", status);
    Ok(())
  } else {
    let text = response.text().await.with_context(|| {
      format!(
        "Failed to send message to ntfy | {status} | failed to get response text"
      )
    })?;
    Err(anyhow!(
      "Failed to send message to ntfy | {status} | {text}",
    ))
  }
}

fn http_client() -> &'static reqwest::Client {
  static CLIENT: OnceLock<reqwest::Client> = OnceLock::new();
  CLIENT.get_or_init(reqwest::Client::new)
}
