use std::{fmt::Display, sync::OnceLock};

pub static NO_DECORATION: OnceLock<bool> = OnceLock::new();
pub static DEBUG: OnceLock<bool> = OnceLock::new();

#[macro_export]
macro_rules! log_context {
  ($($name:ident => $value:expr),* $(,)?) => {{
    use heck::ToTitleCase;
    let ctx = file!()
      .split('/')
      .last()
      .unwrap_or("unknown")
      .split('.')
      .next()
      .unwrap_or("unknown")
      .to_title_case();
    println!("{}", ctx);
    let last = [$(stringify!($name)),*].last().unwrap();
    let maxlen = [$(stringify!($name)),*].iter().map(|s| s.len()).max().unwrap_or(0) + 1;
    $(
        let marker = if stringify!($name) == *last { '╰' } else { '├' };
        println!(
            "{} {:width$}: {:?}",
            marker,
            stringify!($name),
            $value,
            width = maxlen
        );
    )*
    println!();
}};
}

#[macro_export]
macro_rules! debug {
  ($fmt:expr) => {{
    if *$crate::log::DEBUG.get().unwrap_or(&false) {
      println!($fmt);
    }
  }};
  ($fmt:expr, $($arg:tt)*) => {{
    if *$crate::log::DEBUG.get().unwrap_or(&false) {
      println!($fmt, $($arg)*);
    }
  }};
}

#[allow(dead_code)]
pub trait Ansi {
    fn fg(&self, color: u8) -> String;
    fn bg(&self, color: u8) -> String;
    fn bold(&self) -> String;
    fn link(&self, url: &str) -> String;
}

impl<T: Display> Ansi for T {
    fn fg(&self, color: u8) -> String {
        if *NO_DECORATION.get().unwrap_or(&false) {
            return self.to_string();
        }
        format!("\x1b[38;5;{}m{}\x1b[39m", color, self)
    }
    fn bg(&self, color: u8) -> String {
        if *NO_DECORATION.get().unwrap_or(&false) {
            return self.to_string();
        }
        format!("\x1b[48;5;{}m{}\x1b[49m", color, self)
    }
    fn bold(&self) -> String {
        if *NO_DECORATION.get().unwrap_or(&false) {
            return self.to_string();
        }
        format!("\x1b[1m{}\x1b[22m", self)
    }
    fn link(&self, url: &str) -> String {
        if *NO_DECORATION.get().unwrap_or(&false) {
            return self.to_string();
        }
        format!("\x1b]8;;{}\x1b\\{}\x1b]8;;\x1b\\", url, self)
    }
}
