use crate::kmain::KERNEL_CONF;
use crate::network::socket::{SimpleSock, Socket};
use crate::time::fetch_time;
use lliw::{Fg, Reset};
use log::{Level, Metadata, Record};
use log::{LevelFilter, 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) {
        if self.enabled(record.metadata()) {
            let time_float = fetch_time();

            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()
            );
            // kprint!("{}", msg);
            // NOTE: This needs to be fixed before merge
            if KERNEL_CONF.logging.log_to_serial {
                // #[track_caller]

                serial_println!(
                    "[{}{}{}][{}{}{}] {}",
                    color.0,
                    record.level(),
                    Fg::Reset,
                    Fg::Green,
                    time_float,
                    Reset,
                    record.args()
                );
            }

            let log_socket_id = SimpleSock::grab_socket("Logger".to_string());
            match log_socket_id {
                Some(mut log_socket_id) => {
                    log_socket_id.write(msg.as_bytes().to_vec());
                }
                None => warn!("No socket found for Logger"),
            }
        }
    }
    /// Clear the log buffer
    fn flush(&self) {}
}

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