use {
    crate::utils::clonecell::CloneCell,
    log::{Level, LevelFilter, Log, Metadata, Record},
    std::{
        fmt::Write as FmtWrite,
        io::Write,
        rc::Rc,
        sync::atomic::{AtomicUsize, Ordering},
        time::SystemTime,
    },
    uapi::{Fd, OwnedFd},
};

static LEVEL: AtomicUsize = AtomicUsize::new(Level::Info as usize);

thread_local! {
    static FILE: CloneCell<Option<Rc<OwnedFd>>> = const { CloneCell::new(None) };
}

pub fn install() {
    let _ = log::set_logger(&Logger);
    log::set_max_level(LevelFilter::Info);
}

pub fn set_level(level: Level) {
    LEVEL.store(level as usize, Ordering::Relaxed);
    log::set_max_level(level.to_level_filter());
}

pub fn set_file(file: Rc<OwnedFd>) {
    FILE.with(|f| f.set(Some(file)));
}

pub fn unset_file() {
    FILE.with(|f| f.set(None));
}

struct Logger;

impl Log for Logger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() as usize <= LEVEL.load(Ordering::Relaxed)
    }

    fn log(&self, record: &Record) {
        if record.level() as usize > LEVEL.load(Ordering::Relaxed) {
            return;
        }
        let mut buf = String::new();
        let now = SystemTime::now();
        let _ = if let Some(mp) = record.module_path() {
            writeln!(
                buf,
                "[{} {:5} {}] {}",
                humantime::format_rfc3339_millis(now),
                record.level(),
                mp,
                record.args(),
            )
        } else {
            writeln!(
                buf,
                "[{} {:5}] {}",
                humantime::format_rfc3339_millis(now),
                record.level(),
                record.args(),
            )
        };
        let mut fd = match FILE.with(|f| f.get()) {
            Some(f) => f.borrow(),
            _ => Fd::new(2),
        };
        let _ = fd.write_all(buf.as_bytes());
    }

    fn flush(&self) {
        // nothing
    }
}
