macro_rules! impl_handler_tuple {
    ($barrier:ident => $($handler_ty:ident $handler_var:ident),+ $(,)?) => {
        impl<$($handler_ty),+> HandlerTuple for ($(RegisteredHandler<$handler_ty>,)+)
        where
            $($handler_ty: EventHandler<EngineEvent> + Send + 'static,)+
        {
            fn startup_recovery_plan(&self, snapshot_seq: u64) -> StartupRecoveryPlan {
                let ($($handler_var,)+) = self;
                let mut plan = StartupRecoveryPlan {
                    scan_floor: snapshot_seq,
                    required_through_seq: None,
                };
                $(
                    $handler_var.update_recovery_plan(snapshot_seq, &mut plan);
                )+
                plan
            }

            fn validate_cursors(
                &self,
                incomplete_tail: Option<IncompleteTailTx>,
                recoverable_head: u64,
            ) -> anyhow::Result<()> {
                let ($($handler_var,)+) = self;
                $(
                    $handler_var.validate_cursor(incomplete_tail, recoverable_head)?;
                )+
                Ok(())
            }

            fn replay_event(
                &mut self,
                event: &JournalEvent,
                sequence: disrupt_rs::Sequence,
                end_of_batch: bool,
                replay_event: &mut Option<EngineEvent>,
            ) {
                let ($($handler_var,)+) = self;
                $(
                    $handler_var.replay_event(event, sequence, end_of_batch, replay_event);
                )+
            }
        }

        impl<W, $($handler_ty),+> AttachHandlers<W> for ($(RegisteredHandler<$handler_ty>,)+)
        where
            W: WaitStrategy + Clone + Send + 'static,
            $($handler_ty: EventHandler<EngineEvent> + Send + 'static,)+
        {
            type Barrier = $barrier;

            fn attach(
                self,
                builder: NcBuilder<W>,
            ) -> disrupt_rs::SingleProducer<EngineEvent, Self::Barrier, W> {
                let ($($handler_var,)+) = self;
                $(
                    let builder = configure_handler_builder(builder, $handler_var.core_settings)
                        .handle_events_with($handler_var.handler);
                )+
                builder.build()
            }
        }
    };
}

pub(crate) use impl_handler_tuple;

macro_rules! impl_many_handler_builder {
    ($(($($handler_ty:ident $handler_var:ident),+) => $next_ty:ident),+ $(,)?) => {
        $(
            impl<W, $($handler_ty),+> EngineBuilder<McBuilder<W>, W, ($(RegisteredHandler<$handler_ty>,)+)>
            where
                W: WaitStrategy + Clone + Send + 'static,
                $($handler_ty: EventHandler<EngineEvent> + Send + 'static,)+
            {
                pub fn build(self) -> anyhow::Result<Engine> {
                    build_engine_with_handlers(self)
                }

                pub fn register_handler<$next_ty>(
                    self,
                    handler: $next_ty,
                    recovery: HandlerRecovery,
                    core_settings: CoreSettings,
                ) -> EngineBuilder<McBuilder<W>, W, ($(RegisteredHandler<$handler_ty>,)+ RegisteredHandler<$next_ty>,)>
                where
                    $next_ty: EventHandler<EngineEvent> + Send + 'static,
                {
                    self.map_handlers::<McBuilder<W>, _>(|($($handler_var,)+)| {
                        (
                            $($handler_var,)+
                            RegisteredHandler::new(handler, recovery, core_settings),
                        )
                    })
                }
            }
        )+
    };
}

pub(crate) use impl_many_handler_builder;
