use std::sync::OnceLock;
use std::thread;
use std::time::Duration;


use syslog_rs::formatters::{DefaultSyslogFormatterFile};
use syslog_rs::{SyslogApi, QueuedSyslog};
use syslog_rs::sync::DefaultQueueAdapter;
use syslog_rs::{LogFacility, LogStat, Priority, SyslogFile};
use syslog_rs::AsyncSyslogQueueApi;
use tokio::sync::{mpsc};
use tokio::{runtime, task};

pub static SYSLOG: OnceLock<QueuedSyslog<DefaultQueueAdapter, DefaultSyslogFormatterFile, SyslogFile>> = OnceLock::new();


macro_rules! logdebug 
{
    ($($arg:tt)*) => (
        SYSLOG.get().as_ref().unwrap().syslog(Priority::LOG_DEBUG, format!($($arg)*).into())
    )
}

macro_rules! alogdebug 
{
    ($($arg:tt)*) => (
        SYSLOG.get().as_ref().unwrap().a_syslog(Priority::LOG_DEBUG, format!($($arg)*).into()).await
    )
}


pub fn main()
{
    SYSLOG.get_or_init(move || {
        QueuedSyslog
            ::<_, DefaultSyslogFormatterFile, SyslogFile>
            ::openlog_with(
                Some("example_logtofile"), 
                LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
                LogFacility::LOG_DAEMON,
                SyslogFile::new("/tmp/example_logtofile.txt")
            )
            .unwrap()
    });
    

    logdebug!("test message logtofile!");

    thread::sleep(Duration::from_micros(10));

    let runtime = 
        runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .unwrap();

    runtime.block_on(async 
        {
            let s =
                task::spawn_blocking(move || 
                    {
                        for i in 0..10
                        {
                            logdebug!("blocking thread 1 message no: '{}'", i);
                        
                            thread::sleep(Duration::from_micros(300));
                        }

                        return;
                    }
                );

            for i in 0..10
            {
                alogdebug!("async thread message no: '{}'", i);

                tokio::time::sleep(Duration::from_micros(304)).await;
            }

            s.await.unwrap();

            let (tx, mut rx) = mpsc::channel::<u64>(1);

            task::spawn_blocking(move || 
                {
                    SYSLOG.get().unwrap().update_tap_data(SyslogFile::new("/tmp/example_logtofile2.txt")).unwrap();

                    tx.blocking_send(0).unwrap();

                    for i in 0..10
                    {
                        logdebug!("blocking NEW thread message no: '{}'", i);
                    
                        thread::sleep(Duration::from_micros(300));
                    }
                    return;
                }
            );

            rx.recv().await;

            for i in 0..10
            {
                alogdebug!("async NEW thread message no: '{}'", i);

                tokio::time::sleep(Duration::from_micros(304)).await;
            }
        }
    );

    logdebug!("test message logtofile!");

    return;
}

