Documentation
use std::io;
use std::io::Write;

use crate::terminal::{INPUT_BUFFER, PROMPT};
use tracing::{warn, Level};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::fmt::time::OffsetTime;
use tracing_subscriber::fmt::writer::MakeWriterExt;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;

pub fn init_logger() -> [WorkerGuard; 3] {
    let local_offset = time::UtcOffset::current_local_offset();

    let time_format =
        time::format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]").unwrap();

    let (s, s_guard) = tracing_appender::non_blocking(LogStdoutWriter);

    let stdout_layer = tracing_subscriber::fmt::layer()
        .with_target(false)
        .with_writer(s.with_max_level(Level::DEBUG));

    let file_writer = tracing_appender::rolling::daily("log", "atri_bot.log");
    let (f, f_guard) = tracing_appender::non_blocking(file_writer);

    let file_layer = tracing_subscriber::fmt::layer()
        .with_target(false)
        .with_ansi(false)
        .with_writer(f.with_max_level(Level::INFO));

    let file_error_writer = tracing_appender::rolling::daily("log/error", "atri_bot.err");
    let (f_err, f_err_guard) = tracing_appender::non_blocking(file_error_writer);

    let file_error_layer = tracing_subscriber::fmt::layer()
        .with_target(false)
        .with_ansi(false)
        .with_writer(f_err.with_max_level(Level::ERROR));

    let (offset, err) = match local_offset {
        Ok(ofs) => (ofs, None),
        Err(e) => (time::UtcOffset::from_hms(8, 0, 0).unwrap(), Some(e)),
    };

    let timer = OffsetTime::new(offset, time_format);
    let (stdout_layer, file_layer, file_error_layer) = (
        stdout_layer.with_timer(timer.clone()),
        file_layer.with_timer(timer.clone()),
        file_error_layer.with_timer(timer),
    );

    tracing_subscriber::registry()
        .with(stdout_layer)
        .with(file_layer)
        .with(file_error_layer)
        .init();

    if let Some(e) = err {
        warn!("初始化日志时间错误: {}, 使用默认时区UTC+8", e);
    }

    [s_guard, f_guard, f_err_guard]
}

pub struct LogStdoutWriter;

impl Default for LogStdoutWriter {
    fn default() -> Self {
        Self
    }
}

impl Write for LogStdoutWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut stdout = io::stdout().lock();

        stdout.write_all(&[13])?;
        let size = stdout.write(buf)?;

        stdout.write_all(PROMPT)?;
        stdout.write_all(INPUT_BUFFER.read().unwrap().as_bytes())?;
        stdout.flush()?;

        Ok(size)
    }

    fn flush(&mut self) -> io::Result<()> {
        io::stdout().flush()
    }
}