use std::collections::HashMap;
use chrono::prelude::*;

pub struct Log;

impl Log {
    const GRAY: &'static str = "\x1b[90m"; // ANSI escape code for gray color
    const RESET: &'static str = "\x1b[0m"; // ANSI escape code to reset color

    pub fn log(text: &str, kwargs: Option<&HashMap<&str, &str>>) {
        let log_message = if let Some(kwargs) = kwargs {
            format!(
                "{} {}",
                text,
                kwargs
                    .iter()
                    .map(|(key, value)| format!("{}{}={}{}", Self::GRAY, key, Self::RESET, value))
                    .collect::<Vec<String>>()
                    .join(" ")
            )
        } else {
            text.to_string()
        };

        let timestamp = Log::get_timestamp();
        println!("{}{} {}", Self::GRAY, timestamp, log_message);
    }

    pub fn debug(text: &str, kwargs: Option<&HashMap<&str, &str>>) {
        let light_blue = "\x1b[94m";
        let timestamp = Log::get_timestamp();
        let log_message = match kwargs {
            Some(kwargs) => format!(
                "[DBG] {} {}",
                text,
                kwargs
                    .iter()
                    .map(|(key, value)| format!("{}{}={}{}", Self::GRAY, key, Self::RESET, value))
                    .collect::<Vec<String>>()
                    .join(" ")
            ),
            None => format!("{}[{}DBG{}]{} {}", Self::GRAY, light_blue, Self::GRAY, Self::RESET, text),
        };
        println!("{}{} {}", Self::GRAY, timestamp, log_message);
    }

    fn get_timestamp() -> String {
        let dt = Local::now();
        dt.format("%H:%M:%S").to_string()
    }
}

#[macro_export]
macro_rules! logwithargs {
    ($text:expr, {$($key:expr => $value:expr),*}) => {{
        let mut kwargs = std::collections::HashMap::new();
        $(kwargs.insert($key, $value);)*
        Log::log($text, Some(&kwargs));
    }};
}


#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_log_function() {
        let kwargs = {
            let mut kwargs = HashMap::new();
            kwargs.insert("key1", "value1");
            kwargs.insert("key2", "value2");
            kwargs
        };

        Log::log("Test Logging:", Some(&kwargs));
        // Include assertions to validate the output or behavior
        // assert_eq!(expected_value, actual_value);
    }

    #[test]
    fn test_debug_function() {
        let kwargs = {
            let mut kwargs = HashMap::new();
            kwargs.insert("key1", "value1");
            kwargs.insert("key2", "value2");
            kwargs
        };

        Log::debug("Test Debugging:", Some(&kwargs));
        // Include assertions to validate the output or behavior
        // assert_eq!(expected_value, actual_value);
    }
}
