use anyhow::Result;
use fern::colors::{Color, ColoredLevelConfig};
use log::{LevelFilter, debug};
use std::fs::create_dir_all;
use std::str::FromStr;
use std::{env, thread};

/// Set up the logger with a given package name
///
/// # Errors
/// If an error occurred while trying to set up the logger
pub fn setup_logger(package_name: &'static str) -> Result<()> {
    let log_file = env::var("LOG_FILE").or_else(|_| {
        create_dir_all("logs/")?;

        anyhow::Ok(format!(
            "logs/{}_{}.log",
            package_name,
            chrono::Local::now().format("%Y%m%d_%H%M%S")
        ))
    })?;
    let log_level = match env::var("LOG_LEVEL") {
        Ok(log_level) => log::LevelFilter::from_str(&log_level).unwrap_or(log::LevelFilter::Info),
        Err(_) => log::LevelFilter::Info,
    };

    let colors = ColoredLevelConfig::new()
        .error(Color::Red)
        .warn(Color::Yellow)
        .info(Color::White)
        .debug(Color::White)
        .trace(Color::BrightBlack);

    fern::Dispatch::new()
        .format(move |out, message, record| {
            let binding = thread::current();
            let thread_name = binding.name().unwrap_or("<unnamed>");

            out.finish(format_args!(
                "[{time} {level} {thread_name} {target}] {message}",
                level = colors.color(record.level()),
                time = chrono::Local::now().format("%Y-%m-%dT%H:%M:%S%.9f"),
                target = record.target(),
            ));
        })
        .level_for("tungstenite", LevelFilter::Warn)
        .level_for("tokio_tungstenite", LevelFilter::Warn)
        .level_for("microlp", LevelFilter::Warn)
        .level_for("api", LevelFilter::Info)
        .chain(
            fern::Dispatch::new()
                .level(log_level)
                .chain(std::io::stdout()),
        )
        .chain(fern::log_file(log_file.clone())?)
        .apply()?;

    debug!("Logging to {log_file} at level {log_level}");
    Ok(())
}
