use env_logger::{
	fmt::{Color, Formatter},
	Builder as LogBuilder,
};
use log::LevelFilter;
use std::io::{IsTerminal, Write};

#[derive(Debug, PartialEq, Clone)]
pub struct Config {
	pub mode: Option<String>,
	pub color: bool,
	pub file: Option<String>,
}

impl Default for Config {
	fn default() -> Self {
		Config { mode: None, color: !cfg!(windows), file: None }
	}
}

pub static LOG_ENABLED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true);

pub fn setup_log(config: &Config) {
	let mut levels = String::new();
	let mut builder = LogBuilder::new();

	builder.filter(None, LevelFilter::Info);

	if let Ok(lvl) = std::env::var("RUST_LOG") {
		levels.push_str(&lvl);
		levels.push(',');
		builder.parse_filters(&lvl);
	}

	if let Some(ref s) = config.mode {
		levels.push_str(s);
		builder.parse_filters(s);
	}

	let isatty = std::io::stderr().is_terminal();
	let enable_color = config.color && isatty;

	let format = move |buf: &mut Formatter, record: &log::Record| {
		let mut bold = buf.style();
		bold.set_bold(true);
		let mut blue_bold = buf.style();
		blue_bold.set_color(Color::Blue).set_bold(true);

		let dt = chrono::Local::now();
		let timestamp = dt.format("%Y-%m-%d %H:%M:%S%.6f");

		let with_color = if enable_color && log::max_level() <= LevelFilter::Info {
			format!("{} {}", bold.value(timestamp), record.args(),)
		} else {
			let id = std::thread::current().id();
			format!(
				"{} {:?} {} {}  {}",
				bold.value(timestamp),
				id,
				record.level(),
				record.target(),
				record.args()
			)
		};

		if !isatty && record.level() <= log::Level::Info && std::io::stdout().is_terminal() {
			// duplicate INFO/WARN output to console
			println!("{with_color}");
		}

		if LOG_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
			writeln!(buf, "{with_color}")?;
		}
		Ok(())
	};

	builder.format(format);
	let _ = builder.try_init();
}
