/// Wrapper for `iced::daemon`.
///
/// This is a workaround for `clippy --all-target` and rust-analyzer issue that
/// happens when this crate is used with `"testing"` feature enabled in
/// dev-dependencies. These tools then "leak" the `"testing"` feature into
/// checks of non-test code.
///
/// This is unfortunately quite involved due to all the stuff it requires (see
/// `dependencies` below).
pub fn daemon<State, Message, Theme, Renderer>(
    boot: impl BootFn<State, Message>,
    update: impl UpdateFn<State, Message>,
    view: impl for<'a> iced::daemon::ViewFn<'a, State, Message, Theme, Renderer>,
) -> Daemon<impl Program<State = State, Message = Message, Theme = Theme>>
where
    State: 'static,
    Message: Send + 'static,
    Theme: Default + iced::theme::Base,
    Renderer: iced_program::Renderer,
{
    #[cfg(not(any(test, feature = "testing")))]
    {
        iced::daemon(boot, update, view)
    }

    #[cfg(any(test, feature = "testing"))]
    {
        let _ = (boot, update, view);
        Daemon {
            _raw: DummyProgram {
                phantom: std::marker::PhantomData,
            },
        }
    }
}

pub use depedencies::*;

#[cfg(not(any(test, feature = "testing")))]
mod depedencies {
    pub use iced::application::{BootFn, UpdateFn};
    pub use iced::{Daemon, Program};
}

#[cfg(any(test, feature = "testing"))]
mod depedencies {
    pub trait BootFn<State, Message> {}

    #[cfg(any(test, feature = "testing"))]
    impl<T, State, Message> BootFn<State, Message> for T {}

    #[cfg(any(test, feature = "testing"))]
    pub trait UpdateFn<State, Message> {}

    #[cfg(any(test, feature = "testing"))]
    impl<T, State, Message> UpdateFn<State, Message> for T {}

    #[cfg(any(test, feature = "testing"))]
    pub trait Program {
        type State;
        type Message;
        type Theme;
    }

    #[cfg(any(test, feature = "testing"))]
    pub struct Daemon<P: Program> {
        pub _raw: P,
    }

    #[cfg(any(test, feature = "testing"))]
    pub struct DummyProgram<State, Message, Theme> {
        pub phantom: std::marker::PhantomData<(State, Message, Theme)>,
    }

    #[cfg(any(test, feature = "testing"))]
    impl<State, Message, Theme> Program for DummyProgram<State, Message, Theme> {
        type State = State;
        type Message = Message;
        type Theme = Theme;
    }

    #[cfg(any(test, feature = "testing"))]
    impl<P: Program> Daemon<P> {
        pub fn subscription(
            self,
            f: impl Fn(&P::State) -> iced::Subscription<P::Message>,
        ) -> Daemon<P> {
            let _ = (self, f);
            unimplemented!()
        }

        pub fn theme(
            self,
            f: impl Fn(&P::State, iced::window::Id) -> P::Theme,
        ) -> Daemon<P> {
            let _ = (self, f);
            unimplemented!()
        }

        pub fn title(
            self,
            title: impl iced::daemon::TitleFn<P::State>,
        ) -> Daemon<P> {
            let _ = (self, title);
            unimplemented!()
        }

        pub fn run(self) -> iced::Result
        where
            Self: 'static,
        {
            let _ = self;
            unimplemented!()
        }
    }
}