use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
use sync::Mutex;
use super::Event;
use super::EventWaitResult;
use super::FakeClock;
use super::RawDescriptor;
use super::Result;
use crate::descriptor::AsRawDescriptor;
use crate::descriptor::FromRawDescriptor;
use crate::descriptor::IntoRawDescriptor;
use crate::descriptor::SafeDescriptor;
pub trait TimerTrait: AsRawDescriptor + IntoRawDescriptor + Send {
    fn reset_oneshot(&mut self, dur: Duration) -> Result<()>;
    fn reset_repeating(&mut self, dur: Duration) -> Result<()>;
    fn wait(&mut self) -> Result<()>;
    fn mark_waited(&mut self) -> Result<bool>;
    fn clear(&mut self) -> Result<()>;
    fn resolution(&self) -> Result<Duration>;
}
pub struct Timer {
    pub(crate) handle: SafeDescriptor,
    pub(crate) interval: Option<Duration>,
}
impl Timer {
    pub fn try_clone(&self) -> std::result::Result<Timer, std::io::Error> {
        self.handle
            .try_clone()
            .map(|handle| Timer {
                handle,
                interval: self.interval,
            })
            .map_err(|err| std::io::Error::from_raw_os_error(err.errno()))
    }
}
#[derive(PartialEq, Eq, Debug)]
enum WaitResult {
    Expired,
    Timeout,
}
impl AsRawDescriptor for Timer {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        self.handle.as_raw_descriptor()
    }
}
impl FromRawDescriptor for Timer {
    unsafe fn from_raw_descriptor(handle: RawDescriptor) -> Self {
        Timer {
            handle: SafeDescriptor::from_raw_descriptor(handle),
            interval: None,
        }
    }
}
impl IntoRawDescriptor for Timer {
    fn into_raw_descriptor(self) -> RawDescriptor {
        self.handle.into_raw_descriptor()
    }
}
pub struct FakeTimer {
    clock: Arc<Mutex<FakeClock>>,
    deadline_ns: Option<u64>,
    interval: Option<Duration>,
    event: Event,
}
impl FakeTimer {
    pub fn new(clock: Arc<Mutex<FakeClock>>) -> Self {
        FakeTimer {
            clock,
            deadline_ns: None,
            interval: None,
            event: Event::new().unwrap(),
        }
    }
    fn reset(&mut self, dur: Duration) -> Result<()> {
        let mut guard = self.clock.lock();
        let deadline = guard.nanos() + dur.as_nanos() as u64;
        self.deadline_ns = Some(deadline);
        guard.add_event(deadline, self.event.try_clone()?);
        Ok(())
    }
    fn wait_for(&mut self, timeout: Option<Duration>) -> Result<WaitResult> {
        let wait_start = Instant::now();
        loop {
            if let Some(timeout) = timeout {
                let elapsed = Instant::now() - wait_start;
                if let Some(remaining) = elapsed.checked_sub(timeout) {
                    if let EventWaitResult::TimedOut = self.event.wait_timeout(remaining)? {
                        return Ok(WaitResult::Timeout);
                    }
                } else {
                    return Ok(WaitResult::Timeout);
                }
            } else {
                self.event.wait()?;
            }
            if let Some(deadline_ns) = &mut self.deadline_ns {
                let mut guard = self.clock.lock();
                let now = guard.nanos();
                if now >= *deadline_ns {
                    let mut expirys = 0;
                    if let Some(interval) = self.interval {
                        let interval_ns = interval.as_nanos() as u64;
                        if interval_ns > 0 {
                            expirys += (now - *deadline_ns) / interval_ns;
                            *deadline_ns += (expirys + 1) * interval_ns;
                            guard.add_event(*deadline_ns, self.event.try_clone()?);
                        }
                    }
                    return Ok(WaitResult::Expired);
                }
            }
        }
    }
}
impl TimerTrait for FakeTimer {
    fn reset_oneshot(&mut self, dur: Duration) -> Result<()> {
        self.interval = None;
        self.reset(dur)
    }
    fn reset_repeating(&mut self, dur: Duration) -> Result<()> {
        self.interval = Some(dur);
        self.reset(dur)
    }
    fn wait(&mut self) -> Result<()> {
        self.wait_for(None).map(|_| ())
    }
    fn mark_waited(&mut self) -> Result<bool> {
        if let WaitResult::Timeout = self.wait_for(Some(Duration::from_secs(0)))? {
            Ok(true)
        } else {
            Ok(false)
        }
    }
    fn clear(&mut self) -> Result<()> {
        self.deadline_ns = None;
        self.interval = None;
        Ok(())
    }
    fn resolution(&self) -> Result<Duration> {
        Ok(Duration::from_nanos(1))
    }
}
impl AsRawDescriptor for FakeTimer {
    fn as_raw_descriptor(&self) -> RawDescriptor {
        self.event.as_raw_descriptor()
    }
}
impl IntoRawDescriptor for FakeTimer {
    fn into_raw_descriptor(self) -> RawDescriptor {
        self.event.into_raw_descriptor()
    }
}
#[cfg(test)]
mod tests {
    use std::time::Duration;
    #[cfg(not(windows))]
    use std::time::Instant;
    use super::*;
    use crate::EventToken;
    use crate::WaitContext;
    #[test]
    #[cfg(not(windows))] fn one_shot() {
        let mut tfd = Timer::new().expect("failed to create Timer");
        let dur = Duration::from_millis(10);
        let now = Instant::now();
        tfd.reset_oneshot(dur).expect("failed to arm timer");
        tfd.wait().expect("unable to wait for timer");
        let elapsed = now.elapsed();
        assert!(elapsed >= dur, "expected {:?} >= {:?}", elapsed, dur);
    }
    #[test]
    #[cfg(not(windows))] fn one_shot_cloned() {
        let mut tfd = Timer::new().expect("failed to create Timer");
        let mut cloned_tfd = tfd.try_clone().expect("failed to clone timer");
        let dur = Duration::from_millis(10);
        let now = Instant::now();
        tfd.reset_oneshot(dur).expect("failed to arm timer");
        cloned_tfd.wait().expect("unable to wait for timer");
        let elapsed = now.elapsed();
        assert!(elapsed >= dur, "expected {:?} >= {:?}", elapsed, dur);
    }
    #[test]
    #[cfg(not(windows))] fn repeating() {
        let mut tfd = Timer::new().expect("failed to create Timer");
        let interval = Duration::from_millis(10);
        let now = Instant::now();
        tfd.reset_repeating(interval).expect("failed to arm timer");
        tfd.wait().expect("unable to wait for timer");
        assert!(now.elapsed() >= interval);
        tfd.wait().expect("unable to wait for timer");
        assert!(now.elapsed() >= interval * 2);
        tfd.wait().expect("unable to wait for timer");
        assert!(now.elapsed() >= interval * 3);
    }
    #[test]
    fn mark_waited_inactive() {
        let mut tfd = Timer::new().expect("failed to create Timer");
        tfd.mark_waited().expect("mark_waited failed");
    }
    #[test]
    fn mark_waited_active() {
        let mut tfd = Timer::new().expect("failed to create Timer");
        tfd.reset_oneshot(Duration::from_nanos(1))
            .expect("failed to arm timer");
        #[derive(EventToken)]
        enum Token {
            Timer,
        }
        let wait_ctx: WaitContext<Token> =
            WaitContext::build_with(&[(&tfd, Token::Timer)]).unwrap();
        let _events = wait_ctx.wait().unwrap();
        assert!(
            !tfd.mark_waited().expect("mark_waited failed"),
            "expected mark_waited to return false",
        );
    }
    #[test]
    fn fake_one_shot() {
        let clock = Arc::new(Mutex::new(FakeClock::new()));
        let mut tfd = FakeTimer::new(clock.clone());
        let dur = Duration::from_nanos(200);
        tfd.reset_oneshot(dur).expect("failed to arm timer");
        clock.lock().add_ns(200);
        assert_eq!(tfd.wait().is_ok(), true);
    }
    #[test]
    fn fake_one_shot_timeout() {
        let clock = Arc::new(Mutex::new(FakeClock::new()));
        let mut tfd = FakeTimer::new(clock.clone());
        let dur = Duration::from_nanos(200);
        tfd.reset_oneshot(dur).expect("failed to arm timer");
        clock.lock().add_ns(100);
        let result = tfd
            .wait_for(Some(Duration::from_millis(0)))
            .expect("unable to wait for timer");
        assert_eq!(result, WaitResult::Timeout);
        let result = tfd
            .wait_for(Some(Duration::from_millis(1)))
            .expect("unable to wait for timer");
        assert_eq!(result, WaitResult::Timeout);
        clock.lock().add_ns(100);
        let result = tfd
            .wait_for(Some(Duration::from_millis(0)))
            .expect("unable to wait for timer");
        assert_eq!(result, WaitResult::Expired);
    }
    #[test]
    fn fake_repeating() {
        let clock = Arc::new(Mutex::new(FakeClock::new()));
        let mut tfd = FakeTimer::new(clock.clone());
        let interval = Duration::from_nanos(100);
        tfd.reset_repeating(interval).expect("failed to arm timer");
        clock.lock().add_ns(150);
        assert_eq!(tfd.wait().is_ok(), true);
        clock.lock().add_ns(100);
        assert_eq!(tfd.wait().is_ok(), true);
    }
}