use std::cell::{Cell, RefCell};
use std::fmt::Debug;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::{io, slice};

#[cfg(feature = "block_on")]
use std::future::Future;

#[cfg(unix)]
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsHandle, AsRawHandle, AsSocket as AsFd, BorrowedHandle, RawHandle};

use log::trace;
use polling::Poller;

use crate::list::{SourceEntry, SourceList};
use crate::sources::{Dispatcher, EventSource, Idle, IdleDispatcher};
use crate::sys::{Notifier, PollEvent};
use crate::token::TokenInner;
use crate::{
    AdditionalLifecycleEventsSet, InsertError, Poll, PostAction, Readiness, Token, TokenFactory,
};

type IdleCallback<'i, Data> = Rc<RefCell<dyn IdleDispatcher<Data> + 'i>>;

/// A token representing a registration in the [`EventLoop`].
///
/// This token is given to you by the [`EventLoop`] when an [`EventSource`] is inserted or
/// a [`Dispatcher`] is registered. You can use it to [disable](LoopHandle#method.disable),
/// [enable](LoopHandle#method.enable), [update`](LoopHandle#method.update),
/// [remove](LoopHandle#method.remove) or [kill](LoopHandle#method.kill) it.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RegistrationToken {
    inner: TokenInner,
}

impl RegistrationToken {
    /// Create the RegistrationToken corresponding to the given raw key
    /// This is needed because some methods use `RegistrationToken`s as
    /// raw usizes within this crate
    pub(crate) fn new(inner: TokenInner) -> Self {
        Self { inner }
    }
}

pub(crate) struct LoopInner<'l, Data> {
    pub(crate) poll: RefCell<Poll>,
    // The `Option` is used to keep slots of the slab occipied, to prevent id reuse
    // while in-flight events might still referr to a recently destroyed event source.
    pub(crate) sources: RefCell<SourceList<'l, Data>>,
    pub(crate) sources_with_additional_lifecycle_events: RefCell<AdditionalLifecycleEventsSet>,
    idles: RefCell<Vec<IdleCallback<'l, Data>>>,
    pending_action: Cell<PostAction>,
}

/// An handle to an event loop
///
/// This handle allows you to insert new sources and idles in this event loop,
/// it can be cloned, and it is possible to insert new sources from within a source
/// callback.
pub struct LoopHandle<'l, Data> {
    inner: Rc<LoopInner<'l, Data>>,
}

impl<'l, Data> std::fmt::Debug for LoopHandle<'l, Data> {
    #[cfg_attr(feature = "nightly_coverage", coverage(off))]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("LoopHandle { ... }")
    }
}

impl<'l, Data> Clone for LoopHandle<'l, Data> {
    #[cfg_attr(feature = "nightly_coverage", coverage(off))]
    fn clone(&self) -> Self {
        LoopHandle {
            inner: self.inner.clone(),
        }
    }
}

impl<'l, Data> LoopHandle<'l, Data> {
    /// Inserts a new event source in the loop.
    ///
    /// The provided callback will be called during the dispatching cycles whenever the
    /// associated source generates events, see `EventLoop::dispatch(..)` for details.
    ///
    /// This function takes ownership of the event source. Use `register_dispatcher`
    /// if you need access to the event source after this call.
    pub fn insert_source<S, F>(
        &self,
        source: S,
        callback: F,
    ) -> Result<RegistrationToken, InsertError<S>>
    where
        S: EventSource + 'l,
        F: FnMut(S::Event, &mut S::Metadata, &mut Data) -> S::Ret + 'l,
    {
        let dispatcher = Dispatcher::new(source, callback);
        self.register_dispatcher(dispatcher.clone())
            .map_err(|error| InsertError {
                error,
                inserted: dispatcher.into_source_inner(),
            })
    }

    /// Registers a `Dispatcher` in the loop.
    ///
    /// Use this function if you need access to the event source after its insertion in the loop.
    ///
    /// See also `insert_source`.
    #[cfg_attr(feature = "nightly_coverage", coverage(off))] // Contains a branch we can't hit w/o OOM
    pub fn register_dispatcher<S>(
        &self,
        dispatcher: Dispatcher<'l, S, Data>,
    ) -> crate::Result<RegistrationToken>
    where
        S: EventSource + 'l,
    {
        let mut sources = self.inner.sources.borrow_mut();
        let mut poll = self.inner.poll.borrow_mut();

        // Find an empty slot if any
        let slot = sources.vacant_entry();

        slot.source = Some(dispatcher.clone_as_event_dispatcher());
        trace!("[calloop] Inserting new source #{}", slot.token.get_id());
        let ret = slot.source.as_ref().unwrap().register(
            &mut poll,
            &mut self
                .inner
                .sources_with_additional_lifecycle_events
                .borrow_mut(),
            &mut TokenFactory::new(slot.token),
        );

        if let Err(error) = ret {
            slot.source = None;
            return Err(error);
        }

        Ok(RegistrationToken { inner: slot.token })
    }

    /// Inserts an idle callback.
    ///
    /// This callback will be called during a dispatching cycle when the event loop has
    /// finished processing all pending events from the sources and becomes idle.
    pub fn insert_idle<'i, F: FnOnce(&mut Data) + 'l + 'i>(&self, callback: F) -> Idle<'i> {
        let mut opt_cb = Some(callback);
        let callback = Rc::new(RefCell::new(Some(move |data: &mut Data| {
            if let Some(cb) = opt_cb.take() {
                cb(data);
            }
        })));
        self.inner.idles.borrow_mut().push(callback.clone());
        Idle { callback }
    }

    /// Enables this previously disabled event source.
    ///
    /// This previously disabled source will start generating events again.
    ///
    /// **Note:** this cannot be done from within the source callback.
    pub fn enable(&self, token: &RegistrationToken) -> crate::Result<()> {
        if let &SourceEntry {
            token: entry_token,
            source: Some(ref source),
        } = self.inner.sources.borrow().get(token.inner)?
        {
            trace!("[calloop] Registering source #{}", entry_token.get_id());
            source.register(
                &mut self.inner.poll.borrow_mut(),
                &mut self
                    .inner
                    .sources_with_additional_lifecycle_events
                    .borrow_mut(),
                &mut TokenFactory::new(entry_token),
            )
        } else {
            Err(crate::Error::InvalidToken)
        }
    }

    /// Makes this source update its registration.
    ///
    /// If after accessing the source you changed its parameters in a way that requires
    /// updating its registration.
    pub fn update(&self, token: &RegistrationToken) -> crate::Result<()> {
        if let &SourceEntry {
            token: entry_token,
            source: Some(ref source),
        } = self.inner.sources.borrow().get(token.inner)?
        {
            trace!(
                "[calloop] Updating registration of source #{}",
                entry_token.get_id()
            );
            if !source.reregister(
                &mut self.inner.poll.borrow_mut(),
                &mut self
                    .inner
                    .sources_with_additional_lifecycle_events
                    .borrow_mut(),
                &mut TokenFactory::new(entry_token),
            )? {
                trace!("[calloop] Cannot do it now, storing for later.");
                // we are in a callback, store for later processing
                self.inner.pending_action.set(PostAction::Reregister);
            }
            Ok(())
        } else {
            Err(crate::Error::InvalidToken)
        }
    }

    /// Disables this event source.
    ///
    /// The source remains in the event loop, but it'll no longer generate events
    pub fn disable(&self, token: &RegistrationToken) -> crate::Result<()> {
        if let &SourceEntry {
            token: entry_token,
            source: Some(ref source),
        } = self.inner.sources.borrow().get(token.inner)?
        {
            if !token.inner.same_source_as(entry_token) {
                // The token provided by the user is no longer valid
                return Err(crate::Error::InvalidToken);
            }
            trace!("[calloop] Unregistering source #{}", entry_token.get_id());
            if !source.unregister(
                &mut self.inner.poll.borrow_mut(),
                &mut self
                    .inner
                    .sources_with_additional_lifecycle_events
                    .borrow_mut(),
                *token,
            )? {
                trace!("[calloop] Cannot do it now, storing for later.");
                // we are in a callback, store for later processing
                self.inner.pending_action.set(PostAction::Disable);
            }
            Ok(())
        } else {
            Err(crate::Error::InvalidToken)
        }
    }

    /// Removes this source from the event loop.
    pub fn remove(&self, token: RegistrationToken) {
        if let Ok(&mut SourceEntry {
            token: entry_token,
            ref mut source,
        }) = self.inner.sources.borrow_mut().get_mut(token.inner)
        {
            if let Some(source) = source.take() {
                trace!("[calloop] Removing source #{}", entry_token.get_id());
                if let Err(e) = source.unregister(
                    &mut self.inner.poll.borrow_mut(),
                    &mut self
                        .inner
                        .sources_with_additional_lifecycle_events
                        .borrow_mut(),
                    token,
                ) {
                    log::warn!(
                        "[calloop] Failed to unregister source from the polling system: {:?}",
                        e
                    );
                }
            }
        }
    }

    /// Wrap an IO object into an async adapter
    ///
    /// This adapter turns the IO object into an async-aware one that can be used in futures.
    /// The readiness of these futures will be driven by the event loop.
    ///
    /// The produced futures can be polled in any executor, and notably the one provided by
    /// calloop.
    pub fn adapt_io<F: AsFd>(&self, fd: F) -> crate::Result<crate::io::Async<'l, F>> {
        crate::io::Async::new(self.inner.clone(), fd)
    }
}

/// An event loop
///
/// This loop can host several event sources, that can be dynamically added or removed.
pub struct EventLoop<'l, Data> {
    #[allow(dead_code)]
    poller: Arc<Poller>,
    handle: LoopHandle<'l, Data>,
    signals: Arc<Signals>,
    // A caching vector for synthetic poll events
    synthetic_events: Vec<PollEvent>,
}

impl<'l, Data> std::fmt::Debug for EventLoop<'l, Data> {
    #[cfg_attr(feature = "nightly_coverage", coverage(off))]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("EventLoop { ... }")
    }
}

/// Signals related to the event loop.
struct Signals {
    /// Signal to stop the event loop.
    stop: AtomicBool,

    /// Signal that the future is ready.
    #[cfg(feature = "block_on")]
    future_ready: AtomicBool,
}

impl<'l, Data> EventLoop<'l, Data> {
    /// Create a new event loop
    ///
    /// Fails if the initialization of the polling system failed.
    pub fn try_new() -> crate::Result<Self> {
        let poll = Poll::new()?;
        let poller = poll.poller.clone();
        let handle = LoopHandle {
            inner: Rc::new(LoopInner {
                poll: RefCell::new(poll),
                sources: RefCell::new(SourceList::new()),
                idles: RefCell::new(Vec::new()),
                pending_action: Cell::new(PostAction::Continue),
                sources_with_additional_lifecycle_events: Default::default(),
            }),
        };

        Ok(EventLoop {
            handle,
            signals: Arc::new(Signals {
                stop: AtomicBool::new(false),
                #[cfg(feature = "block_on")]
                future_ready: AtomicBool::new(false),
            }),
            poller,
            synthetic_events: vec![],
        })
    }

    /// Retrieve a loop handle
    pub fn handle(&self) -> LoopHandle<'l, Data> {
        self.handle.clone()
    }

    fn dispatch_events(
        &mut self,
        mut timeout: Option<Duration>,
        data: &mut Data,
    ) -> crate::Result<()> {
        let now = Instant::now();
        {
            let mut extra_lifecycle_sources = self
                .handle
                .inner
                .sources_with_additional_lifecycle_events
                .borrow_mut();
            let sources = &self.handle.inner.sources.borrow();
            for source in &mut *extra_lifecycle_sources.values {
                if let Ok(SourceEntry {
                    source: Some(disp), ..
                }) = sources.get(source.inner)
                {
                    if let Some((readiness, token)) = disp.before_sleep()? {
                        // Wake up instantly after polling if we recieved an event
                        timeout = Some(Duration::ZERO);
                        self.synthetic_events.push(PollEvent { readiness, token });
                    }
                } else {
                    unreachable!()
                }
            }
        }
        let events = {
            let poll = self.handle.inner.poll.borrow();
            loop {
                let result = poll.poll(timeout);

                match result {
                    Ok(events) => break events,
                    Err(crate::Error::IoError(err)) if err.kind() == io::ErrorKind::Interrupted => {
                        // Interrupted by a signal. Update timeout and retry.
                        if let Some(to) = timeout {
                            let elapsed = now.elapsed();
                            if elapsed >= to {
                                return Ok(());
                            } else {
                                timeout = Some(to - elapsed);
                            }
                        }
                    }
                    Err(err) => return Err(err),
                };
            }
        };
        {
            let mut extra_lifecycle_sources = self
                .handle
                .inner
                .sources_with_additional_lifecycle_events
                .borrow_mut();
            if !extra_lifecycle_sources.values.is_empty() {
                for source in &mut *extra_lifecycle_sources.values {
                    if let Ok(SourceEntry {
                        source: Some(disp), ..
                    }) = self.handle.inner.sources.borrow().get(source.inner)
                    {
                        let iter = EventIterator {
                            inner: events.iter(),
                            registration_token: *source,
                        };
                        disp.before_handle_events(iter);
                    } else {
                        unreachable!()
                    }
                }
            }
        }

        for event in self.synthetic_events.drain(..).chain(events) {
            // Get the registration token associated with the event.
            let reg_token = event.token.inner.forget_sub_id();

            let opt_disp = self
                .handle
                .inner
                .sources
                .borrow()
                .get(reg_token)
                .ok()
                .and_then(|entry| entry.source.clone());

            if let Some(disp) = opt_disp {
                trace!(
                    "[calloop] Dispatching events for source #{}",
                    reg_token.get_id()
                );
                let mut ret = disp.process_events(event.readiness, event.token, data)?;

                // if the returned PostAction is Continue, it may be overwritten by an user-specified pending action
                let pending_action = self
                    .handle
                    .inner
                    .pending_action
                    .replace(PostAction::Continue);
                if let PostAction::Continue = ret {
                    ret = pending_action;
                }

                match ret {
                    PostAction::Reregister => {
                        trace!(
                            "[calloop] Postaction reregister for source #{}",
                            reg_token.get_id()
                        );
                        disp.reregister(
                            &mut self.handle.inner.poll.borrow_mut(),
                            &mut self
                                .handle
                                .inner
                                .sources_with_additional_lifecycle_events
                                .borrow_mut(),
                            &mut TokenFactory::new(reg_token),
                        )?;
                    }
                    PostAction::Disable => {
                        trace!(
                            "[calloop] Postaction unregister for source #{}",
                            reg_token.get_id()
                        );
                        disp.unregister(
                            &mut self.handle.inner.poll.borrow_mut(),
                            &mut self
                                .handle
                                .inner
                                .sources_with_additional_lifecycle_events
                                .borrow_mut(),
                            RegistrationToken::new(reg_token),
                        )?;
                    }
                    PostAction::Remove => {
                        trace!(
                            "[calloop] Postaction remove for source #{}",
                            reg_token.get_id()
                        );
                        if let Ok(entry) = self.handle.inner.sources.borrow_mut().get_mut(reg_token)
                        {
                            entry.source = None;
                        }
                    }
                    PostAction::Continue => {}
                }

                if self
                    .handle
                    .inner
                    .sources
                    .borrow()
                    .get(reg_token)
                    .ok()
                    .map(|entry| entry.source.is_none())
                    .unwrap_or(true)
                {
                    // the source has been removed from within its callback, unregister it
                    let mut poll = self.handle.inner.poll.borrow_mut();
                    if let Err(e) = disp.unregister(
                        &mut poll,
                        &mut self
                            .handle
                            .inner
                            .sources_with_additional_lifecycle_events
                            .borrow_mut(),
                        RegistrationToken::new(reg_token),
                    ) {
                        log::warn!(
                            "[calloop] Failed to unregister source from the polling system: {:?}",
                            e
                        );
                    }
                }
            } else {
                log::warn!(
                    "[calloop] Received an event for non-existence source: {:?}",
                    reg_token
                );
            }
        }

        Ok(())
    }

    fn dispatch_idles(&mut self, data: &mut Data) {
        let idles = std::mem::take(&mut *self.handle.inner.idles.borrow_mut());
        for idle in idles {
            idle.borrow_mut().dispatch(data);
        }
    }

    /// Dispatch pending events to their callbacks
    ///
    /// If some sources have events available, their callbacks will be immediatly called.
    /// Otherwise this will wait until an event is receive or the provided `timeout`
    /// is reached. If `timeout` is `None`, it will wait without a duration limit.
    ///
    /// Once pending events have been processed or the timeout is reached, all pending
    /// idle callbacks will be fired before this method returns.
    pub fn dispatch<D: Into<Option<Duration>>>(
        &mut self,
        timeout: D,
        data: &mut Data,
    ) -> crate::Result<()> {
        self.dispatch_events(timeout.into(), data)?;
        self.dispatch_idles(data);

        Ok(())
    }

    /// Get a signal to stop this event loop from running
    ///
    /// To be used in conjunction with the `run()` method.
    pub fn get_signal(&self) -> LoopSignal {
        LoopSignal {
            signal: self.signals.clone(),
            notifier: self.handle.inner.poll.borrow().notifier(),
        }
    }

    /// Run this event loop
    ///
    /// This will repeatedly try to dispatch events (see the `dispatch()` method) on
    /// this event loop, waiting at most `timeout` every time.
    ///
    /// Between each dispatch wait, your provided callback will be called.
    ///
    /// You can use the `get_signal()` method to retrieve a way to stop or wakeup
    /// the event loop from anywhere.
    pub fn run<F, D: Into<Option<Duration>>>(
        &mut self,
        timeout: D,
        data: &mut Data,
        mut cb: F,
    ) -> crate::Result<()>
    where
        F: FnMut(&mut Data),
    {
        let timeout = timeout.into();
        self.signals.stop.store(false, Ordering::Release);
        while !self.signals.stop.load(Ordering::Acquire) {
            self.dispatch(timeout, data)?;
            cb(data);
        }
        Ok(())
    }

    /// Block a future on this event loop.
    ///
    /// This will run the provided future on this event loop, blocking until it is
    /// resolved.
    ///
    /// If [`LoopSignal::stop()`] is called before the future is resolved, this function returns
    /// `None`.
    #[cfg(feature = "block_on")]
    pub fn block_on<R>(
        &mut self,
        future: impl Future<Output = R>,
        data: &mut Data,
        mut cb: impl FnMut(&mut Data),
    ) -> crate::Result<Option<R>> {
        use std::task::{Context, Poll, Wake, Waker};

        /// A waker that will wake up the event loop when it is ready to make progress.
        struct EventLoopWaker(LoopSignal);

        impl Wake for EventLoopWaker {
            fn wake(self: Arc<Self>) {
                // Set the waker.
                self.0.signal.future_ready.store(true, Ordering::Release);
                self.0.notifier.notify().ok();
            }

            fn wake_by_ref(self: &Arc<Self>) {
                // Set the waker.
                self.0.signal.future_ready.store(true, Ordering::Release);
                self.0.notifier.notify().ok();
            }
        }

        // Pin the future to the stack.
        pin_utils::pin_mut!(future);

        // Create a waker that will wake up the event loop when it is ready to make progress.
        let waker = {
            let handle = EventLoopWaker(self.get_signal());

            Waker::from(Arc::new(handle))
        };
        let mut context = Context::from_waker(&waker);

        // Begin running the loop.
        let mut output = None;

        self.signals.stop.store(false, Ordering::Release);
        self.signals.future_ready.store(true, Ordering::Release);

        while !self.signals.stop.load(Ordering::Acquire) {
            // If the future is ready to be polled, poll it.
            if self.signals.future_ready.swap(false, Ordering::AcqRel) {
                // Poll the future and break the loop if it's ready.
                if let Poll::Ready(result) = future.as_mut().poll(&mut context) {
                    output = Some(result);
                    break;
                }
            }

            // Otherwise, block on the event loop.
            self.dispatch_events(None, data)?;
            self.dispatch_idles(data);
            cb(data);
        }

        Ok(output)
    }
}

#[cfg(unix)]
impl<'l, Data> AsRawFd for EventLoop<'l, Data> {
    /// Get the underlying raw-fd of the poller.
    ///
    /// This could be used to create [`Generic`] source out of the current loop
    /// and inserting into some other [`EventLoop`]. It's recommended to clone `fd`
    /// before doing so.
    ///
    /// [`Generic`]: crate::generic::Generic
    fn as_raw_fd(&self) -> RawFd {
        self.poller.as_raw_fd()
    }
}

#[cfg(unix)]
impl<'l, Data> AsFd for EventLoop<'l, Data> {
    /// Get the underlying fd of the poller.
    ///
    /// This could be used to create [`Generic`] source out of the current loop
    /// and inserting into some other [`EventLoop`].
    ///
    /// [`Generic`]: crate::generic::Generic
    fn as_fd(&self) -> BorrowedFd<'_> {
        self.poller.as_fd()
    }
}

#[cfg(windows)]
impl<Data> AsRawHandle for EventLoop<'_, Data> {
    fn as_raw_handle(&self) -> RawHandle {
        self.poller.as_raw_handle()
    }
}

#[cfg(windows)]
impl<Data> AsHandle for EventLoop<'_, Data> {
    fn as_handle(&self) -> BorrowedHandle<'_> {
        self.poller.as_handle()
    }
}

#[derive(Clone, Debug)]
/// The EventIterator is an `Iterator` over the events relevant to a particular source
/// This type is used in the [`EventSource::before_handle_events`] methods for
/// two main reasons:
/// - To avoid dynamic dispatch overhead
/// - Secondly, it is to allow this type to be `Clone`, which is not
/// possible with dynamic dispatch
pub struct EventIterator<'a> {
    inner: slice::Iter<'a, PollEvent>,
    registration_token: RegistrationToken,
}

impl<'a> Iterator for EventIterator<'a> {
    type Item = (Readiness, Token);

    fn next(&mut self) -> Option<Self::Item> {
        for next in self.inner.by_ref() {
            if next
                .token
                .inner
                .same_source_as(self.registration_token.inner)
            {
                return Some((next.readiness, next.token));
            }
        }
        None
    }
}

/// A signal that can be shared between thread to stop or wakeup a running
/// event loop
#[derive(Clone)]
pub struct LoopSignal {
    signal: Arc<Signals>,
    notifier: Notifier,
}

impl std::fmt::Debug for LoopSignal {
    #[cfg_attr(feature = "nightly_coverage", coverage(off))]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("LoopSignal { ... }")
    }
}

impl LoopSignal {
    /// Stop the event loop
    ///
    /// Once this method is called, the next time the event loop has finished
    /// waiting for events, it will return rather than starting to wait again.
    ///
    /// This is only useful if you are using the `EventLoop::run()` method.
    pub fn stop(&self) {
        self.signal.stop.store(true, Ordering::Release);
    }

    /// Wake up the event loop
    ///
    /// This sends a dummy event to the event loop to simulate the reception
    /// of an event, making the wait return early. Called after `stop()`, this
    /// ensures the event loop will terminate quickly if you specified a long
    /// timeout (or no timeout at all) to the `dispatch` or `run` method.
    pub fn wakeup(&self) {
        self.notifier.notify().ok();
    }
}

#[cfg(test)]
mod tests {
    use std::{cell::Cell, rc::Rc, time::Duration};

    use crate::{
        channel::{channel, Channel},
        ping::*,
        EventIterator, EventSource, Poll, PostAction, Readiness, RegistrationToken, Token,
        TokenFactory,
    };

    #[cfg(unix)]
    use crate::{generic::Generic, Dispatcher, Interest, Mode};

    use super::EventLoop;

    #[test]
    fn dispatch_idle() {
        let mut event_loop = EventLoop::try_new().unwrap();

        let mut dispatched = false;

        event_loop.handle().insert_idle(|d| {
            *d = true;
        });

        event_loop
            .dispatch(Some(Duration::ZERO), &mut dispatched)
            .unwrap();

        assert!(dispatched);
    }

    #[test]
    fn cancel_idle() {
        let mut event_loop = EventLoop::try_new().unwrap();

        let mut dispatched = false;

        let handle = event_loop.handle();
        let idle = handle.insert_idle(move |d| {
            *d = true;
        });

        idle.cancel();

        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();

        assert!(!dispatched);
    }

    #[test]
    fn wakeup() {
        let mut event_loop = EventLoop::try_new().unwrap();

        let signal = event_loop.get_signal();

        ::std::thread::spawn(move || {
            ::std::thread::sleep(Duration::from_millis(500));
            signal.wakeup();
        });

        // the test should return
        event_loop.dispatch(None, &mut ()).unwrap();
    }

    #[test]
    fn wakeup_stop() {
        let mut event_loop = EventLoop::try_new().unwrap();

        let signal = event_loop.get_signal();

        ::std::thread::spawn(move || {
            ::std::thread::sleep(Duration::from_millis(500));
            signal.stop();
            signal.wakeup();
        });

        // the test should return
        event_loop.run(None, &mut (), |_| {}).unwrap();
    }

    #[test]
    fn additional_events() {
        let mut event_loop: EventLoop<'_, Lock> = EventLoop::try_new().unwrap();
        let mut lock = Lock {
            lock: Rc::new((
                // Whether the lock is locked
                Cell::new(false),
                // The total number of events processed in process_events
                Cell::new(0),
                // The total number of events processed in before_handle_events
                // This is used to ensure that the count seen in before_handle_events is expected
                Cell::new(0),
            )),
        };
        let (sender, channel) = channel();
        let token = event_loop
            .handle()
            .insert_source(
                LockingSource {
                    channel,
                    lock: lock.clone(),
                },
                |_, _, lock| {
                    lock.lock();
                    lock.unlock();
                },
            )
            .unwrap();
        sender.send(()).unwrap();

        event_loop.dispatch(None, &mut lock).unwrap();
        // We should have been locked twice so far
        assert_eq!(lock.lock.1.get(), 2);
        // And we should have received one event
        assert_eq!(lock.lock.2.get(), 1);
        event_loop.handle().disable(&token).unwrap();
        event_loop
            .dispatch(Some(Duration::ZERO), &mut lock)
            .unwrap();
        assert_eq!(lock.lock.1.get(), 2);

        event_loop.handle().enable(&token).unwrap();
        event_loop
            .dispatch(Some(Duration::ZERO), &mut lock)
            .unwrap();
        assert_eq!(lock.lock.1.get(), 3);
        event_loop.handle().remove(token);
        event_loop
            .dispatch(Some(Duration::ZERO), &mut lock)
            .unwrap();
        assert_eq!(lock.lock.1.get(), 3);
        assert_eq!(lock.lock.2.get(), 1);

        #[derive(Clone)]
        struct Lock {
            lock: Rc<(Cell<bool>, Cell<u32>, Cell<u32>)>,
        }
        impl Lock {
            fn lock(&self) {
                if self.lock.0.get() {
                    panic!();
                }
                // Increase the count
                self.lock.1.set(self.lock.1.get() + 1);
                self.lock.0.set(true)
            }
            fn unlock(&self) {
                if !self.lock.0.get() {
                    panic!();
                }
                self.lock.0.set(false);
            }
        }
        struct LockingSource {
            channel: Channel<()>,
            lock: Lock,
        }
        impl EventSource for LockingSource {
            type Event = <Channel<()> as EventSource>::Event;

            type Metadata = <Channel<()> as EventSource>::Metadata;

            type Ret = <Channel<()> as EventSource>::Ret;

            type Error = <Channel<()> as EventSource>::Error;

            fn process_events<F>(
                &mut self,
                readiness: Readiness,
                token: Token,
                callback: F,
            ) -> Result<PostAction, Self::Error>
            where
                F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
            {
                self.channel.process_events(readiness, token, callback)
            }

            fn register(
                &mut self,
                poll: &mut Poll,
                token_factory: &mut TokenFactory,
            ) -> crate::Result<()> {
                self.channel.register(poll, token_factory)
            }

            fn reregister(
                &mut self,
                poll: &mut Poll,
                token_factory: &mut TokenFactory,
            ) -> crate::Result<()> {
                self.channel.reregister(poll, token_factory)
            }

            fn unregister(&mut self, poll: &mut Poll) -> crate::Result<()> {
                self.channel.unregister(poll)
            }

            const NEEDS_EXTRA_LIFECYCLE_EVENTS: bool = true;

            fn before_sleep(&mut self) -> crate::Result<Option<(Readiness, Token)>> {
                self.lock.lock();
                Ok(None)
            }

            fn before_handle_events(&mut self, events: EventIterator) {
                let events_count = events.count();
                let lock = &self.lock.lock;
                lock.2.set(lock.2.get() + events_count as u32);
                self.lock.unlock();
            }
        }
    }
    #[test]
    fn default_additional_events() {
        let (sender, channel) = channel();
        let mut test_source = NoopWithDefaultHandlers { channel };
        let mut event_loop = EventLoop::try_new().unwrap();
        event_loop
            .handle()
            .insert_source(Box::new(&mut test_source), |_, _, _| {})
            .unwrap();
        sender.send(()).unwrap();

        event_loop.dispatch(None, &mut ()).unwrap();
        struct NoopWithDefaultHandlers {
            channel: Channel<()>,
        }
        impl EventSource for NoopWithDefaultHandlers {
            type Event = <Channel<()> as EventSource>::Event;

            type Metadata = <Channel<()> as EventSource>::Metadata;

            type Ret = <Channel<()> as EventSource>::Ret;

            type Error = <Channel<()> as EventSource>::Error;

            fn process_events<F>(
                &mut self,
                readiness: Readiness,
                token: Token,
                callback: F,
            ) -> Result<PostAction, Self::Error>
            where
                F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
            {
                self.channel.process_events(readiness, token, callback)
            }

            fn register(
                &mut self,
                poll: &mut Poll,
                token_factory: &mut TokenFactory,
            ) -> crate::Result<()> {
                self.channel.register(poll, token_factory)
            }

            fn reregister(
                &mut self,
                poll: &mut Poll,
                token_factory: &mut TokenFactory,
            ) -> crate::Result<()> {
                self.channel.reregister(poll, token_factory)
            }

            fn unregister(&mut self, poll: &mut Poll) -> crate::Result<()> {
                self.channel.unregister(poll)
            }

            const NEEDS_EXTRA_LIFECYCLE_EVENTS: bool = true;
        }
    }

    #[test]
    fn additional_events_synthetic() {
        let mut event_loop: EventLoop<'_, Lock> = EventLoop::try_new().unwrap();
        let mut lock = Lock {
            lock: Rc::new(Cell::new(false)),
        };
        event_loop
            .handle()
            .insert_source(
                InstantWakeupLockingSource {
                    lock: lock.clone(),
                    token: None,
                },
                |_, _, lock| {
                    lock.lock();
                    lock.unlock();
                },
            )
            .unwrap();

        // Loop should finish, as
        event_loop.dispatch(None, &mut lock).unwrap();
        #[derive(Clone)]
        struct Lock {
            lock: Rc<Cell<bool>>,
        }
        impl Lock {
            fn lock(&self) {
                if self.lock.get() {
                    panic!();
                }
                self.lock.set(true)
            }
            fn unlock(&self) {
                if !self.lock.get() {
                    panic!();
                }
                self.lock.set(false);
            }
        }
        struct InstantWakeupLockingSource {
            lock: Lock,
            token: Option<Token>,
        }
        impl EventSource for InstantWakeupLockingSource {
            type Event = ();

            type Metadata = ();

            type Ret = ();

            type Error = <Channel<()> as EventSource>::Error;

            fn process_events<F>(
                &mut self,
                _: Readiness,
                token: Token,
                mut callback: F,
            ) -> Result<PostAction, Self::Error>
            where
                F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
            {
                assert_eq!(token, self.token.unwrap());
                callback((), &mut ());
                Ok(PostAction::Continue)
            }

            fn register(
                &mut self,
                _: &mut Poll,
                token_factory: &mut TokenFactory,
            ) -> crate::Result<()> {
                self.token = Some(token_factory.token());
                Ok(())
            }

            fn reregister(&mut self, _: &mut Poll, _: &mut TokenFactory) -> crate::Result<()> {
                unreachable!()
            }

            fn unregister(&mut self, _: &mut Poll) -> crate::Result<()> {
                unreachable!()
            }

            const NEEDS_EXTRA_LIFECYCLE_EVENTS: bool = true;

            fn before_sleep(&mut self) -> crate::Result<Option<(Readiness, Token)>> {
                self.lock.lock();
                Ok(Some((Readiness::EMPTY, self.token.unwrap())))
            }

            fn before_handle_events(&mut self, _: EventIterator) {
                self.lock.unlock();
            }
        }
    }

    #[cfg(unix)]
    #[test]
    fn insert_bad_source() {
        use std::os::unix::io::FromRawFd;

        let event_loop = EventLoop::<()>::try_new().unwrap();
        let fd = unsafe { std::os::unix::io::OwnedFd::from_raw_fd(420) };
        let ret = event_loop.handle().insert_source(
            crate::sources::generic::Generic::new(fd, Interest::READ, Mode::Level),
            |_, _, _| Ok(PostAction::Continue),
        );
        assert!(ret.is_err());
    }

    #[test]
    fn invalid_token() {
        let (_ping, source) = crate::sources::ping::make_ping().unwrap();

        let event_loop = EventLoop::<()>::try_new().unwrap();
        let handle = event_loop.handle();
        let reg_token = handle.insert_source(source, |_, _, _| {}).unwrap();
        handle.remove(reg_token);

        let ret = handle.enable(&reg_token);
        assert!(ret.is_err());
    }

    #[cfg(unix)]
    #[test]
    fn insert_source_no_interest() {
        use rustix::pipe::pipe;

        // Create a pipe to get an arbitrary fd.
        let (read, _write) = pipe().unwrap();

        let source = crate::sources::generic::Generic::new(read, Interest::EMPTY, Mode::Level);
        let dispatcher = Dispatcher::new(source, |_, _, _| Ok(PostAction::Continue));

        let event_loop = EventLoop::<()>::try_new().unwrap();
        let handle = event_loop.handle();
        let ret = handle.register_dispatcher(dispatcher.clone());

        if let Ok(token) = ret {
            // Unwrap the dispatcher+source and close the read end.
            handle.remove(token);
        } else {
            // Fail the test.
            panic!();
        }
    }

    #[test]
    fn disarm_rearm() {
        let mut event_loop = EventLoop::<bool>::try_new().unwrap();
        let (ping, ping_source) = make_ping().unwrap();

        let ping_token = event_loop
            .handle()
            .insert_source(ping_source, |(), &mut (), dispatched| {
                *dispatched = true;
            })
            .unwrap();

        ping.ping();
        let mut dispatched = false;
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert!(dispatched);

        // disable the source
        ping.ping();
        event_loop.handle().disable(&ping_token).unwrap();
        let mut dispatched = false;
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert!(!dispatched);

        // reenable it, the previous ping now gets dispatched
        event_loop.handle().enable(&ping_token).unwrap();
        let mut dispatched = false;
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert!(dispatched);
    }

    #[test]
    fn multiple_tokens() {
        struct DoubleSource {
            ping1: PingSource,
            ping2: PingSource,
        }

        impl crate::EventSource for DoubleSource {
            type Event = u32;
            type Metadata = ();
            type Ret = ();
            type Error = PingError;

            fn process_events<F>(
                &mut self,
                readiness: Readiness,
                token: Token,
                mut callback: F,
            ) -> Result<PostAction, Self::Error>
            where
                F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
            {
                self.ping1
                    .process_events(readiness, token, |(), &mut ()| callback(1, &mut ()))?;
                self.ping2
                    .process_events(readiness, token, |(), &mut ()| callback(2, &mut ()))?;
                Ok(PostAction::Continue)
            }

            fn register(
                &mut self,
                poll: &mut Poll,
                token_factory: &mut TokenFactory,
            ) -> crate::Result<()> {
                self.ping1.register(poll, token_factory)?;
                self.ping2.register(poll, token_factory)?;
                Ok(())
            }

            fn reregister(
                &mut self,
                poll: &mut Poll,
                token_factory: &mut TokenFactory,
            ) -> crate::Result<()> {
                self.ping1.reregister(poll, token_factory)?;
                self.ping2.reregister(poll, token_factory)?;
                Ok(())
            }

            fn unregister(&mut self, poll: &mut Poll) -> crate::Result<()> {
                self.ping1.unregister(poll)?;
                self.ping2.unregister(poll)?;
                Ok(())
            }
        }

        let mut event_loop = EventLoop::<u32>::try_new().unwrap();

        let (ping1, source1) = make_ping().unwrap();
        let (ping2, source2) = make_ping().unwrap();

        let source = DoubleSource {
            ping1: source1,
            ping2: source2,
        };

        event_loop
            .handle()
            .insert_source(source, |i, _, d| {
                eprintln!("Dispatching {}", i);
                *d += i
            })
            .unwrap();

        let mut dispatched = 0;
        ping1.ping();
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert_eq!(dispatched, 1);

        dispatched = 0;
        ping2.ping();
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert_eq!(dispatched, 2);

        dispatched = 0;
        ping1.ping();
        ping2.ping();
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert_eq!(dispatched, 3);
    }

    #[cfg(unix)]
    #[test]
    fn change_interests() {
        use rustix::io::write;
        use rustix::net::{recv, socketpair, AddressFamily, RecvFlags, SocketFlags, SocketType};
        let mut event_loop = EventLoop::<bool>::try_new().unwrap();

        let (sock1, sock2) = socketpair(
            AddressFamily::UNIX,
            SocketType::STREAM,
            SocketFlags::empty(),
            None, // recv with DONTWAIT will suffice for platforms without SockFlag::SOCK_NONBLOCKING such as macOS
        )
        .unwrap();

        let source = Generic::new(sock1, Interest::READ, Mode::Level);
        let dispatcher = Dispatcher::new(source, |_, fd, dispatched| {
            *dispatched = true;
            // read all contents available to drain the socket
            let mut buf = [0u8; 32];
            loop {
                match recv(&*fd, &mut buf, RecvFlags::DONTWAIT) {
                    Ok(0) => break, // closed pipe, we are now inert
                    Ok(_) => {}
                    Err(e) => {
                        let e: std::io::Error = e.into();
                        if e.kind() == std::io::ErrorKind::WouldBlock {
                            break;
                        // nothing more to read
                        } else {
                            // propagate error
                            return Err(e);
                        }
                    }
                }
            }
            Ok(PostAction::Continue)
        });

        let sock_token_1 = event_loop
            .handle()
            .register_dispatcher(dispatcher.clone())
            .unwrap();

        // first dispatch, nothing is readable
        let mut dispatched = false;
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert!(!dispatched);

        // write something, the socket becomes readable
        write(&sock2, &[1, 2, 3]).unwrap();
        dispatched = false;
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert!(dispatched);

        // All has been read, no longer readable
        dispatched = false;
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert!(!dispatched);

        // change the interests for writability instead
        dispatcher.as_source_mut().interest = Interest::WRITE;
        event_loop.handle().update(&sock_token_1).unwrap();

        // the socket is writable
        dispatched = false;
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert!(dispatched);

        // change back to readable
        dispatcher.as_source_mut().interest = Interest::READ;
        event_loop.handle().update(&sock_token_1).unwrap();

        // the socket is not readable
        dispatched = false;
        event_loop
            .dispatch(Duration::ZERO, &mut dispatched)
            .unwrap();
        assert!(!dispatched);
    }

    #[test]
    fn kill_source() {
        let mut event_loop = EventLoop::<Option<RegistrationToken>>::try_new().unwrap();

        let handle = event_loop.handle();
        let (ping, ping_source) = make_ping().unwrap();
        let ping_token = event_loop
            .handle()
            .insert_source(ping_source, move |(), &mut (), opt_src| {
                if let Some(src) = opt_src.take() {
                    handle.remove(src);
                }
            })
            .unwrap();

        ping.ping();

        let mut opt_src = Some(ping_token);

        event_loop.dispatch(Duration::ZERO, &mut opt_src).unwrap();

        assert!(opt_src.is_none());
    }

    #[test]
    fn non_static_data() {
        use std::sync::mpsc;

        let (sender, receiver) = mpsc::channel();

        {
            struct RefSender<'a>(&'a mpsc::Sender<()>);
            let mut ref_sender = RefSender(&sender);

            let mut event_loop = EventLoop::<RefSender<'_>>::try_new().unwrap();
            let (ping, ping_source) = make_ping().unwrap();
            let _ping_token = event_loop
                .handle()
                .insert_source(ping_source, |_, _, ref_sender| {
                    ref_sender.0.send(()).unwrap();
                })
                .unwrap();

            ping.ping();

            event_loop
                .dispatch(Duration::ZERO, &mut ref_sender)
                .unwrap();
        }

        receiver.recv().unwrap();
        // sender still usable (e.g. for another EventLoop)
        drop(sender);
    }

    #[cfg(feature = "block_on")]
    #[test]
    fn block_on_test() {
        use crate::sources::timer::TimeoutFuture;
        use std::time::Duration;

        let mut evl = EventLoop::<()>::try_new().unwrap();

        let mut data = 22;
        let timeout = {
            let data = &mut data;
            let evl_handle = evl.handle();

            async move {
                TimeoutFuture::from_duration(&evl_handle, Duration::from_secs(2)).await;
                *data = 32;
                11
            }
        };

        let result = evl.block_on(timeout, &mut (), |&mut ()| {}).unwrap();
        assert_eq!(result, Some(11));
        assert_eq!(data, 32);
    }

    #[cfg(feature = "block_on")]
    #[test]
    fn block_on_early_cancel() {
        use crate::sources::timer;
        use std::time::Duration;

        let mut evl = EventLoop::<()>::try_new().unwrap();

        let mut data = 22;
        let timeout = {
            let data = &mut data;
            let evl_handle = evl.handle();

            async move {
                timer::TimeoutFuture::from_duration(&evl_handle, Duration::from_secs(2)).await;
                *data = 32;
                11
            }
        };

        let timer_source = timer::Timer::from_duration(Duration::from_secs(1));
        let handle = evl.get_signal();
        let _timer_token = evl
            .handle()
            .insert_source(timer_source, move |_, _, _| {
                handle.stop();
                timer::TimeoutAction::Drop
            })
            .unwrap();

        let result = evl.block_on(timeout, &mut (), |&mut ()| {}).unwrap();
        assert_eq!(result, None);
        assert_eq!(data, 22);
    }

    #[test]
    fn reuse() {
        use crate::sources::timer;
        use std::sync::{Arc, Mutex};
        use std::time::{Duration, Instant};

        let mut evl = EventLoop::<RegistrationToken>::try_new().unwrap();
        let handle = evl.handle();

        let data = Arc::new(Mutex::new(1));
        let data_cloned = data.clone();

        let timer_source = timer::Timer::from_duration(Duration::from_secs(1));
        let mut first_timer_token = evl
            .handle()
            .insert_source(timer_source, move |_, _, own_token| {
                handle.remove(*own_token);
                let data_cloned = data_cloned.clone();
                let _ = handle.insert_source(timer::Timer::immediate(), move |_, _, _| {
                    *data_cloned.lock().unwrap() = 2;
                    timer::TimeoutAction::Drop
                });
                timer::TimeoutAction::Drop
            })
            .unwrap();

        let now = Instant::now();
        loop {
            evl.dispatch(Some(Duration::from_secs(3)), &mut first_timer_token)
                .unwrap();
            if Instant::now().duration_since(now) > Duration::from_secs(3) {
                break;
            }
        }

        assert_eq!(*data.lock().unwrap(), 2);
    }

    #[test]
    fn drop_of_subsource() {
        struct WithSubSource {
            token: Option<Token>,
        }

        impl crate::EventSource for WithSubSource {
            type Event = ();
            type Metadata = ();
            type Ret = ();
            type Error = crate::Error;
            const NEEDS_EXTRA_LIFECYCLE_EVENTS: bool = true;

            fn process_events<F>(
                &mut self,
                _: Readiness,
                _: Token,
                mut callback: F,
            ) -> Result<PostAction, Self::Error>
            where
                F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
            {
                callback((), &mut ());
                // Drop the source
                Ok(PostAction::Remove)
            }

            fn register(&mut self, _: &mut Poll, fact: &mut TokenFactory) -> crate::Result<()> {
                // produce a few tokens to emulate a subsource
                fact.token();
                fact.token();
                self.token = Some(fact.token());
                Ok(())
            }

            fn reregister(&mut self, _: &mut Poll, _: &mut TokenFactory) -> crate::Result<()> {
                Ok(())
            }

            fn unregister(&mut self, _: &mut Poll) -> crate::Result<()> {
                Ok(())
            }

            // emulate a readiness
            fn before_sleep(&mut self) -> crate::Result<Option<(Readiness, Token)>> {
                Ok(self.token.map(|token| {
                    (
                        Readiness {
                            readable: true,
                            writable: false,
                            error: false,
                        },
                        token,
                    )
                }))
            }
        }

        // Now the actual test
        let mut evl = EventLoop::<bool>::try_new().unwrap();
        evl.handle()
            .insert_source(WithSubSource { token: None }, |_, _, ran| {
                *ran = true;
            })
            .unwrap();

        let mut ran = false;

        evl.dispatch(Some(Duration::ZERO), &mut ran).unwrap();

        assert!(ran);
    }

    // A dummy EventSource to test insertion and removal of sources
    struct DummySource;

    impl crate::EventSource for DummySource {
        type Event = ();
        type Metadata = ();
        type Ret = ();
        type Error = crate::Error;

        fn process_events<F>(
            &mut self,
            _: Readiness,
            _: Token,
            mut callback: F,
        ) -> Result<PostAction, Self::Error>
        where
            F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
        {
            callback((), &mut ());
            Ok(PostAction::Continue)
        }

        fn register(&mut self, _: &mut Poll, _: &mut TokenFactory) -> crate::Result<()> {
            Ok(())
        }

        fn reregister(&mut self, _: &mut Poll, _: &mut TokenFactory) -> crate::Result<()> {
            Ok(())
        }

        fn unregister(&mut self, _: &mut Poll) -> crate::Result<()> {
            Ok(())
        }
    }
}
