use std::{
    sync::mpsc::{Receiver, channel},
    thread::JoinHandle, time::Duration,
};

use crate::defer;

pub struct ThreadWaiter<T> {
    handle: JoinHandle<T>,
    chan: Receiver<()>,
    done: bool,
}

pub fn spawn<T, F>(fun: F) -> ThreadWaiter<T>
where
    T: Send + 'static,
    F: Send + 'static,
    F: FnOnce() -> T,
{
    let (tx, rx) = channel();

    let handle = std::thread::spawn(move || {
        defer! {
            let _ = tx.send(());
        };
        fun()
    });

    ThreadWaiter {
        handle,
        chan: rx,
        done: false,
    }
}

impl<T> ThreadWaiter<T> {
    pub fn try_join(&mut self, timeout_ms: u16) -> bool {
        if self.done {
            return true;
        }

        if let Ok(()) = self.chan.recv_timeout(Duration::from_millis(timeout_ms as _)) {
            self.done = true;
        }

        self.done
    }
    pub fn into_inner(self) -> JoinHandle<T> {
        self.handle
    }
}
