use crate::{kmain::KERNEL_CONF, time::fetch_time};
use lliw::Fg;
use log::{Level, LevelFilter, Metadata, Record, SetLoggerError};

static LOGGER: SimpleLogger = SimpleLogger;
// TODO: Rebuild this to take advantage of sockets
// DETAIL: Log to a socket instead of the screen
// So that we can log in the kernel and display it in userland
struct SimpleLogger;
impl log::Log for SimpleLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= Level::Trace
    }
    fn log(&self, record: &Record) {
        x86_64::instructions::interrupts::without_interrupts(|| {
            if self.enabled(record.metadata()) {
                let time_float = fetch_time();
                use Fg::*;

                let color = match record.level() {
                    log::Level::Error => (Fg::Red, "$RED$"),
                    log::Level::Warn => (Fg::LightYellow, "$LIGHTYELLOW$"),
                    log::Level::Info => (Fg::LightWhite, "$LIGHTGRAY$"),
                    log::Level::Debug => (Fg::Blue, "$BLUE$"),
                    log::Level::Trace => (Fg::Yellow, "$YELLOW$"),
                };

                /*
                let msg = format!(
                    "[{}{}$RESET$][$GREEN${}$RESET$]{}\n",
                    color.1,
                    record.level(),
                    time_float,
                    record.args()
                );
                */
                let mod_path = match record.module_path() {
                    Some(p) => {
                        if KERNEL_CONF.logging.filter.contains(&p.to_string()) {
                            return;
                        }

                        p
                    }
                    None => "unknown",
                };

                let line = match record.line() {
                    Some(line_number) => line_number,
                    None => 0,
                };

                if KERNEL_CONF.logging.log_to_serial {
                    serial_println!(
                        "[{}{}{}][{}{}{}][{}{}@{}{}] {}",
                        color.0,
                        record.level(),
                        Fg::Reset,
                        Fg::Green,
                        time_float,
                        Reset,
                        Fg::Blue,
                        mod_path,
                        line,
                        Reset,
                        record.args()
                    );
                }
            }
        });
    }
    /// Clear the log buffer
    fn flush(&self) {}
}

pub fn init() -> Result<(), SetLoggerError> {
    log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Trace))
    // ?;

    // trace!("Logger started");

    // Ok(())
}
