use std::fmt;

fn is_unicode_supported() -> bool {
	if cfg!(windows) {
		std::env::var("CI").is_ok()
			|| std::env::var("WT_SESSION").is_ok()
			|| std::env::var("TERM_PROGRAM").is_ok_and(|v| v == "vscode")
			|| std::env::var("TERM").is_ok_and(|v| v == "xterm-256color" || v == "alacritty")
	} else {
		std::env::var("TERM").is_ok_and(|v| v != "dumb" && v != "linux")
	}
}

pub enum Level {
	Debug,
	Info,
	Warn,
	Error,
	Success,
	Start,
}

impl Level {
	fn prefix(&self) -> String {
		let unicode = is_unicode_supported();
		match self {
			Level::Debug => {
				let sym = if unicode { "⚙" } else { "D" };
				format!("\x1b[90m{sym}\x1b[0m")
			}
			Level::Info => {
				let sym = if unicode { "ℹ" } else { "i" };
				format!("\x1b[36m{sym}\x1b[0m")
			}
			Level::Warn => "\x1b[43;30m WARN \x1b[0m".to_string(),
			Level::Error => "\x1b[41;30m ERROR \x1b[0m".to_string(),
			Level::Success => {
				let sym = if unicode { "✔" } else { "√" };
				format!("\x1b[32m{sym}\x1b[0m")
			}
			Level::Start => {
				let sym = if unicode { "◐" } else { "*" };
				format!("\x1b[35m{sym}\x1b[0m")
			}
		}
	}

	fn has_padding(&self) -> bool {
		matches!(self, Level::Warn | Level::Error)
	}
}

pub fn log(level: Level, args: fmt::Arguments<'_>) {
	if level.has_padding() {
		eprintln!("\n{} {}\n", level.prefix(), args);
	} else {
		eprintln!("{} {}", level.prefix(), args);
	}
}

pub fn blue(value: &dyn fmt::Display) -> String {
	format!("\x1b[34m{value}\x1b[0m")
}

pub fn dim(value: &dyn fmt::Display) -> String {
	format!("\x1b[2m{value}\x1b[0m")
}

macro_rules! logger_debug {
    ($($arg:tt)*) => { $crate::logger::log($crate::logger::Level::Debug, format_args!($($arg)*)) };
}

macro_rules! logger_info {
    ($($arg:tt)*) => { $crate::logger::log($crate::logger::Level::Info, format_args!($($arg)*)) };
}

macro_rules! logger_warn {
    ($($arg:tt)*) => { $crate::logger::log($crate::logger::Level::Warn, format_args!($($arg)*)) };
}

macro_rules! logger_error {
    ($($arg:tt)*) => { $crate::logger::log($crate::logger::Level::Error, format_args!($($arg)*)) };
}

macro_rules! logger_success {
    ($($arg:tt)*) => { $crate::logger::log($crate::logger::Level::Success, format_args!($($arg)*)) };
}

macro_rules! logger_start {
    ($($arg:tt)*) => { $crate::logger::log($crate::logger::Level::Start, format_args!($($arg)*)) };
}

pub(crate) use logger_debug;
pub(crate) use logger_error;
pub(crate) use logger_info;
pub(crate) use logger_start;
pub(crate) use logger_success;
pub(crate) use logger_warn;
