use std::time::{SystemTime, UNIX_EPOCH};

pub const INFO: usize = 0;
pub const DEBUG: usize = 1;
pub const WARNING: usize = 2;
pub const ERROR: usize = 3;
pub const FATAL: usize = 4;

pub const LOG_LEVEL: [&str; 5] = [
    "INFO",
    "DEBUG",
    "WARN",
    "ERROR",
    "FATAL",
];

pub fn current_timestamp() -> String {
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or_default();

    let total_seconds = now.as_secs();
    let seconds_in_day = total_seconds % 86400; // Seconds within current day

    let hours = seconds_in_day / 3600;
    let minutes = (seconds_in_day % 3600) / 60;
    let seconds = seconds_in_day % 60;

    format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
}

/// Creates a formatted log message string and returns it
/// 
/// log_levels are:
///     - INFO
///     - DEBUG  
///     - WARNING
///     - ERROR
///     - FATAL
///
/// Returns a formatted string ready for display or further processing.
#[macro_export]
macro_rules! msg {
    ($level:expr, $($arg:tt)*) => {{
        let formatted_msg = format!($($arg)*);
        format!(
          "[{:<5}] [{:<15}:{:<4}] {}\n",
          $crate::LOG_LEVEL[$level].to_string(),
          { std::path::Path::new(file!()).file_name().unwrap().to_str().unwrap_or(file!()) },
          line!(),
          formatted_msg
        )
    }};
}

/// Creates a formatted log message and prints it to stdout
/// 
/// log_levels are:
///     - INFO
///     - DEBUG
///     - WARNING
///     - ERROR
///     - FATAL
///
/// FATAL will cause the thread to panic and stop execution.
#[macro_export]
macro_rules! log {
    ($level:expr, $($arg:tt)*) => {{
        let log_message = $crate::msg!($level, $($arg)*);
        println!("{}", log_message);

        // Handle FATAL level panic
        if $level == $crate::FATAL {
            panic!("Fatal error encountered: {}", format!($($arg)*));
        }
    }};
}

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

    #[test]
    fn test_msg_macro() {
        let info_msg = msg!(INFO, "Test info message");
        assert!(info_msg.contains("INFO"));
        assert!(info_msg.contains("Test info message"));

        let error_msg = msg!(ERROR, "Test error: {}", 42);
        assert!(error_msg.contains("ERROR"));
        assert!(error_msg.contains("Test error: 42"));
    }

    #[test]
    fn test_timestamp() {
        let ts = current_timestamp();
        assert!(ts.contains(":"));
        // Should be in HH:MM:SS format
        assert_eq!(ts.len(), 8);
    }
}

