#![allow(deprecated)]
// TODO: Add a logger api with logger levels and various outputs
pub static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));

use {
    limine::{TerminalRequest, TerminalResponse},
    log::{Level, SetLoggerError},
    spin::{lazy::Lazy, mutex::Mutex},
};

pub fn init() -> Result<(), SetLoggerError> {
    log::set_logger(&crate::logger::Logger)?;
    if cfg!(debug_assertions) {
        log::set_max_level(log::LevelFilter::Debug);
    } else {
        log::set_max_level(log::LevelFilter::Info);
    }

    Lazy::force(&TERMINAL_LOGGER);

    Ok(())
}

struct Logger;
impl log::Log for Logger {
    fn enabled(&self, _metadata: &log::Metadata) -> bool {
        true
    }

    fn log(&self, record: &log::Record) {
        let lvl = record.level();
        let lvl_color = match lvl {
            Level::Error => "160",
            Level::Warn => "172",
            Level::Info => "47",
            Level::Debug => "25",
            Level::Trace => "103",
        };
        let module = record.module_path().unwrap_or_default();
        let line = record.line().unwrap_or_default();
        crate::arch::log(format_args!(
            "\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
            record.args(),
        ))
        .expect("write to serial console");
    }

    fn flush(&self) {}
}

pub struct TermLogger(&'static TerminalResponse);
unsafe impl Send for TermLogger {}
impl TermLogger {
    pub fn new() -> Self {
        static TERM_REQ: TerminalRequest = TerminalRequest::new(0);
        Self(
            TERM_REQ
                .get_response()
                .get()
                .expect("failed to get terminal response"),
        )
    }
}

impl core::fmt::Write for TermLogger {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        if let (Some(w), ts) = (self.0.write(), self.0.terminals()) {
            for term in ts {
                w(term, s);
            }
        }
        Ok(())
    }
}