use std::marker::PhantomData;

use common_enums::DynamicContentType;
use common_utils::{errors::CustomResult, ext_traits::BytesExt};
use domain_types::{
    errors::{ConnectorError, IntegrationError},
    router_data_v2::RouterDataV2,
};
use error_stack::ResultExt;

use crate::types;

/// Trait for connectors that need to dynamically select content types
/// based on runtime conditions such as payment method, flow type, etc.
pub trait ContentTypeSelector<F, FCD, Req, Res> {
    /// Determines the appropriate content type for the given request
    fn get_dynamic_content_type(
        &self,
        req: &RouterDataV2<F, FCD, Req, Res>,
    ) -> CustomResult<DynamicContentType, IntegrationError>;
}

pub trait FlowTypes {
    type Flow;
    type FlowCommonData;
    type Request;
    type Response;
}

impl<F, FCD, Req, Resp> FlowTypes for RouterDataV2<F, FCD, Req, Resp> {
    type Flow = F;
    type FlowCommonData = FCD;
    type Request = Req;
    type Response = Resp;
}

impl<F, FCD, Req, Resp> FlowTypes for &RouterDataV2<F, FCD, Req, Resp> {
    type Flow = F;
    type FlowCommonData = FCD;
    type Request = Req;
    type Response = Resp;
}

pub trait GetFormData {
    fn get_form_data(&self) -> common_utils::request::MultipartData;
}

/// Trait for converting request structures into SOAP XML format
/// Implement this trait for request types that need to be sent as SOAP/XML
pub trait GetSoapXml {
    /// Converts the implementing type into a SOAP XML string
    /// The output should be properly formatted and escaped XML
    fn to_soap_xml(&self) -> String;
}

/// Helper function to validate XML is well-formed
/// This catches malformed XML before sending to the connector
#[inline]
pub(crate) fn validate_xml_structure(xml_str: &str) -> Result<(), String> {
    use quick_xml::{events::Event, Reader};

    let mut reader = Reader::from_str(xml_str);
    reader.trim_text(true);
    reader.check_end_names(true); // Verify open/close tags match

    let mut buf = Vec::new();
    loop {
        match reader.read_event_into(&mut buf) {
            Ok(Event::Eof) => break,
            Err(e) => return Err(format!("XML validation failed: {e}")),
            _ => {}
        }
        buf.clear();
    }

    Ok(())
}

pub struct NoRequestBody;
pub struct NoRequestBodyTemplating;

impl<F, FCD, Req, Resp> TryFrom<RouterDataV2<F, FCD, Req, Resp>> for NoRequestBody {
    type Error = error_stack::Report<IntegrationError>;

    fn try_from(_value: RouterDataV2<F, FCD, Req, Resp>) -> Result<Self, Self::Error> {
        Ok(Self)
    }
}

type RouterDataType<T> = RouterDataV2<
    <T as FlowTypes>::Flow,
    <T as FlowTypes>::FlowCommonData,
    <T as FlowTypes>::Request,
    <T as FlowTypes>::Response,
>;

type ResponseRouterDataType<T, R> = types::ResponseRouterData<
    R,
    RouterDataV2<
        <T as FlowTypes>::Flow,
        <T as FlowTypes>::FlowCommonData,
        <T as FlowTypes>::Request,
        <T as FlowTypes>::Response,
    >,
>;

pub trait BridgeRequestResponse: Send + Sync {
    type RequestBody;
    type ResponseBody;
    type ConnectorInputData: FlowTypes;
    fn request_body(
        &self,
        rd: Self::ConnectorInputData,
    ) -> CustomResult<Self::RequestBody, IntegrationError>
    where
        Self::RequestBody:
            TryFrom<Self::ConnectorInputData, Error = error_stack::Report<IntegrationError>>,
    {
        Self::RequestBody::try_from(rd)
    }

    fn response(
        &self,
        bytes: bytes::Bytes,
        status_code: u16,
    ) -> CustomResult<Self::ResponseBody, ConnectorError>
    where
        Self::ResponseBody: for<'a> serde::Deserialize<'a>,
    {
        if bytes.is_empty() {
            serde_json::from_str("{}").change_context(
                crate::utils::response_deserialization_fail(status_code, "macros: response body did not match the expected format; confirm API version and connector documentation."),
            )
        } else {
            bytes
                .parse_struct(std::any::type_name::<Self::ResponseBody>())
                .change_context(
                    crate::utils::response_deserialization_fail(
                        status_code,
                    "macros: response body did not match the expected format; confirm API version and connector documentation."),
                )
        }
    }

    fn router_data(
        &self,
        response: ResponseRouterDataType<Self::ConnectorInputData, Self::ResponseBody>,
        status_code: u16,
    ) -> CustomResult<RouterDataType<Self::ConnectorInputData>, ConnectorError>
    where
        RouterDataType<Self::ConnectorInputData>: TryFrom<
            ResponseRouterDataType<Self::ConnectorInputData, Self::ResponseBody>,
            Error = error_stack::Report<ConnectorError>,
        >,
    {
        RouterDataType::<Self::ConnectorInputData>::try_from(response).change_context(
            crate::utils::response_handling_fail_for_connector(status_code, "macros"),
        )
    }
}

#[derive(Clone)]
pub struct Bridge<Q, S, T>(pub PhantomData<(Q, S, T)>);

macro_rules! expand_fn_get_request_body {
    ($connector: ident, $curl_res: ty, $flow: ident, $resource_common_data: ty, $request: ident, $response: ty) => {
        paste::paste! {
            fn get_request_body(
                &self,
                _req: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
            ) -> CustomResult<Option<macro_types::RequestContent>, macro_types::IntegrationError>
            {
                // always return None
                Ok(None)
            }
        }
    };
    (
        $connector: ident,
        $curl_req: ty,
        FormData,
        $curl_res: ty,
        $flow: ident,
        $resource_common_data: ty,
        $request: ty,
        $response: ty
    ) => {
        paste::paste! {
            fn get_request_body(
                &self,
                req: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
            ) -> CustomResult<Option<macro_types::RequestContent>, macro_types::IntegrationError>
            {
                let bridge = self.[< $flow:snake >];
                let input_data = [<$connector RouterData>] {
                    connector: self.to_owned(),
                    router_data: req.clone()
};
                let request = bridge.request_body(input_data)?;
                let form_data = <$curl_req as GetFormData>::get_form_data(&request);
                Ok(Some(macro_types::RequestContent::FormData(form_data)))
            }
        }
    };
    (
        $connector: ident,
        $curl_req: ty,
        SoapXml,
        $curl_res: ty,
        $flow: ident,
        $resource_common_data: ty,
        $request: ty,
        $response: ty
    ) => {
        paste::paste! {
            fn get_request_body(
                &self,
                req: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
            ) -> CustomResult<Option<macro_types::RequestContent>, macro_types::IntegrationError>
            {
                let bridge = self.[< $flow:snake >];
                let input_data = [<$connector RouterData>] {
                    connector: self.to_owned(),
                    router_data: req.clone()
};
                let request = bridge.request_body(input_data)?;
                let soap_xml = <$curl_req as GetSoapXml>::to_soap_xml(&request);

                // Validate XML structure before sending
                crate::connectors::macros::validate_xml_structure(&soap_xml)
                    .map_err(|e| {
                        error_stack::report!(domain_types::errors::IntegrationError::RequestEncodingFailed { context: Default::default() })
                            .attach_printable(e)
                    })?;

                Ok(Some(macro_types::RequestContent::RawBytes(soap_xml.into_bytes())))
            }
        }
    };
    (
        $connector: ty,
        $curl_req: ty,
        Dynamic,
        $curl_res: ty,
        $flow: ident,
        $resource_common_data: ty,
        $request: ty,
        $response: ty
    ) => {
        paste::paste! {
            fn get_request_body(
                &self,
                req: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
            ) -> CustomResult<Option<macro_types::RequestContent>, macro_types::IntegrationError>
            {
                use crate::connectors::macros::ContentTypeSelector;

                let bridge = self.[< $flow:snake >];
                let input_data = [< $connector RouterData >] {
                    connector: self.to_owned(),
                    router_data: req.clone()
};
                let request = bridge.request_body(input_data)?;

                // Get dynamic content type based on runtime conditions
                let content_type = self.get_dynamic_content_type(req)?;

                match content_type {
                    common_enums::DynamicContentType::Json => {
                        Ok(Some(macro_types::RequestContent::Json(Box::new(request))))
                    }
                    common_enums::DynamicContentType::FormUrlEncoded => {
                        Ok(Some(macro_types::RequestContent::FormUrlEncoded(Box::new(request))))
                    }
                    common_enums::DynamicContentType::FormData => {
                        let form_data = <$curl_req as GetFormData>::get_form_data(&request);
                        Ok(Some(macro_types::RequestContent::FormData(form_data)))
                    }
                }
            }
        }
    };
    (
        $connector: ty,
        $curl_req: ty,
        $content_type: ident,
        $curl_res: ty,
        $flow: ident,
        $resource_common_data: ty,
        $request: ty,
        $response: ty
    ) => {
        paste::paste! {
            fn get_request_body(
                &self,
                req: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
            ) -> CustomResult<Option<macro_types::RequestContent>, macro_types::IntegrationError>
            {
                let bridge = self.[< $flow:snake >];
                let input_data = [< $connector RouterData >] {
                    connector: self.to_owned(),
                    router_data: req.clone()
};
                let request = bridge.request_body(input_data)?;
                Ok(Some(macro_types::RequestContent::$content_type(Box::new(request))))
            }
        }
    };

    // Hand the JSON-serialised request to `preprocess_request_bytes` so the
    // connector can wrap it (JOSE encrypt, HMAC seal, …) before it hits the
    // wire. Symmetric to `preprocess_response_bytes`.
    (
        $connector: ty,
        $curl_req: ty,
        $content_type: ident,
        $curl_res: ty,
        $flow: ident,
        $resource_common_data: ty,
        $request: ty,
        $response: ty,
        preprocess_request
    ) => {
        paste::paste! {
            fn get_request_body(
                &self,
                req: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
            ) -> CustomResult<Option<macro_types::RequestContent>, macro_types::IntegrationError>
            {
                use error_stack::ResultExt;
                let bridge = self.[< $flow:snake >];
                let input_data = [< $connector RouterData >] {
                    connector: self.to_owned(),
                    router_data: req.clone()
};
                let request = bridge.request_body(input_data)?;
                if let Ok(masked_body) = hyperswitch_masking::masked_serialize(&request) {
                    tracing::info!(
                        connector = stringify!($connector),
                        flow = stringify!($flow),
                        request_body = %masked_body,
                        "connector request body (pre-encoding)"
                    );
                }
                let json_bytes = serde_json::to_vec(&request).change_context(
                    macro_types::IntegrationError::RequestEncodingFailed {
                        context: domain_types::errors::IntegrationErrorContext {
                            suggested_action: Some(
                                "Verify the connector's request struct serialises to JSON cleanly."
                                    .to_string(),
                            ),
                            doc_url: Some(
                                "https://docs.hyperswitch.io/prism/architecture/concepts/error-codes"
                                    .to_string(),
                            ),
                            additional_context: Some(
                                "Failed to JSON-serialise the request body before handing it to \
                                 `preprocess_request_bytes`."
                                    .to_string(),
                            ),
                        },
                    },
                )?;
                let preprocessed = self.preprocess_request_bytes(req, json_bytes)?;
                Ok(Some(macro_types::RequestContent::RawBytes(preprocessed)))
            }
        }
    };
}
pub(crate) use expand_fn_get_request_body;

macro_rules! expand_fn_handle_response {
    // When preprocess_response is enabled - only for connectors that explicitly set it
    ($connector: ident, $flow: ident, $resource_common_data: ty, $request: ty, $response: ty, preprocess_enabled) => {
        fn handle_response_v2(
            &self,
            data: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
            event_builder: Option<&mut events::Event>,
            res: Response,
        ) -> CustomResult<
            RouterDataV2<$flow, $resource_common_data, $request, $response>,
            macro_types::ConnectorError,
        > {
            use error_stack::ResultExt;
            paste::paste! {let bridge = self.[< $flow:snake >];}

            // Apply preprocessing if specified in the macro
            let response_bytes = self
                .preprocess_response_bytes(data, res.response, res.status_code)
                .change_context(crate::utils::response_handling_fail_for_connector(
                    res.status_code,
                    "macros",
                ))?;

            let response_body = bridge.response(response_bytes, res.status_code)?;
            event_builder.map(|i| i.set_connector_response(&response_body));
            let response_router_data = ResponseRouterData {
                response: response_body,
                router_data: data.clone(),
                http_code: res.status_code,
            };
            let result = bridge.router_data(response_router_data, res.status_code)?;
            Ok(result)
        }
    };

    // When preprocess_response is disabled or default
    ($connector: ident, $flow: ident, $resource_common_data: ty, $request: ty, $response: ty, $preprocess_flag:tt) => {
        fn handle_response_v2(
            &self,
            data: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
            event_builder: Option<&mut events::Event>,
            res: Response,
        ) -> CustomResult<
            RouterDataV2<$flow, $resource_common_data, $request, $response>,
            macro_types::ConnectorError,
        > {
            paste::paste! {let bridge = self.[< $flow:snake >];}
            let response_body = bridge.response(res.response, res.status_code)?;
            event_builder.map(|i| i.set_connector_response(&response_body));
            let response_router_data = ResponseRouterData {
                response: response_body,
                router_data: data.clone(),
                http_code: res.status_code,
            };
            let result = bridge.router_data(response_router_data, res.status_code)?;
            Ok(result)
        }
    };
}
pub(crate) use expand_fn_handle_response;

macro_rules! expand_default_functions {
    (
        function: get_headers,
        flow_name:$flow: ident,
        resource_common_data:$resource_common_data: ty,
        flow_request:$request: ty,
        flow_response:$response: ty,
    ) => {
        fn get_headers(
            &self,
            req: &RouterDataV2<$flow, $resource_common_data, $request, $response>,
        ) -> macro_types::CustomResult<
            Vec<(String, macro_types::Maskable<String>)>,
            macro_types::IntegrationError,
        > {
            self.build_headers(req)
        }
    };
    (
        function: get_content_type,
        flow_name:$flow: ident,
        resource_common_data:$resource_common_data: ty,
        flow_request:$request: ty,
        flow_response:$response: ty,
    ) => {
        fn get_content_type(&self) -> &'static str {
            self.common_get_content_type()
        }
    };
    (
        function: get_error_response_v2,
        flow_name:$flow: ident,
        resource_common_data:$resource_common_data: ty,
        flow_request:$request: ty,
        flow_response:$response: ty,
    ) => {
        fn get_error_response_v2(
            &self,
            res: Response,
            event_builder: Option<&mut events::Event>,
            connector_config: &macro_types::ConnectorSpecificConfig,
        ) -> CustomResult<ErrorResponse, macro_types::ConnectorError> {
            self.build_error_response(res, event_builder, connector_config)
        }
    };
}
pub(crate) use expand_default_functions;

macro_rules! macro_connector_implementation {
    // Most specific arm: both preprocess hooks enabled. Used by connectors
    // that wrap the body in a cryptographic envelope on both directions.
    (
        connector_default_implementations: [$($function_name: ident), *],
        connector: $connector: ident,
        curl_request: $content_type:ident($curl_req: ty),
        curl_response:$curl_res: ty,
        flow_name:$flow: ident,
        resource_common_data:$resource_common_data: ty,
        flow_request:$request: ty,
        flow_response:$response: ty,
        http_method: $http_method_type:ident,
        preprocess_request: true,
        preprocess_response: true,
        generic_type: $generic_type:tt,
        [$($bounds:tt)*],
        other_functions: {
            $($function_def: tt)*
        }
    ) => {
        impl <$generic_type: $($bounds)*>
            ConnectorIntegrationV2<
                $flow,
                $resource_common_data,
                $request,
                $response,
            > for $connector<$generic_type>
        {
            fn get_http_method(&self) -> common_utils::request::Method {
                common_utils::request::Method::$http_method_type
            }
            $($function_def)*
            $(
                macros::expand_default_functions!(
                    function: $function_name,
                    flow_name:$flow,
                    resource_common_data:$resource_common_data,
                    flow_request:$request,
                    flow_response:$response,
                );
            )*
            macros::expand_fn_get_request_body!(
                $connector,
                $curl_req,
                $content_type,
                $curl_res,
                $flow,
                $resource_common_data,
                $request,
                $response,
                preprocess_request
            );
            macros::expand_fn_handle_response!(
                $connector,
                $flow,
                $resource_common_data,
                $request,
                $response,
                preprocess_enabled
            );
        }
    };

    // Version with preprocess_response: true and curl_request
    (
        connector_default_implementations: [$($function_name: ident), *],
        connector: $connector: ident,
        curl_request: $content_type:ident($curl_req: ty),
        curl_response:$curl_res: ty,
        flow_name:$flow: ident,
        resource_common_data:$resource_common_data: ty,
        flow_request:$request: ty,
        flow_response:$response: ty,
        http_method: $http_method_type:ident,
        preprocess_response: true,
        generic_type: $generic_type:tt,
        [$($bounds:tt)*],
        other_functions: {
            $($function_def: tt)*
        }
    ) => {
        impl <$generic_type: $($bounds)*>
            ConnectorIntegrationV2<
                $flow,
                $resource_common_data,
                $request,
                $response,
            > for $connector<$generic_type>
        {
            fn get_http_method(&self) -> common_utils::request::Method {
                common_utils::request::Method::$http_method_type
            }
            $($function_def)*
            $(
                macros::expand_default_functions!(
                    function: $function_name,
                    flow_name:$flow,
                    resource_common_data:$resource_common_data,
                    flow_request:$request,
                    flow_response:$response,
                );
            )*
            macros::expand_fn_get_request_body!(
                $connector,
                $curl_req,
                $content_type,
                $curl_res,
                $flow,
                $resource_common_data,
                $request,
                $response
            );
            macros::expand_fn_handle_response!(
                $connector,
                $flow,
                $resource_common_data,
                $request,
                $response,
                preprocess_enabled
            );
        }
    };

    // Version with preprocess_response: true but no curl_request
    (
        connector_default_implementations: [$($function_name: ident), *],
        connector: $connector: ident,
        curl_response:$curl_res: ty,
        flow_name:$flow: ident,
        resource_common_data:$resource_common_data: ty,
        flow_request:$request: ty,
        flow_response:$response: ty,
        http_method: $http_method_type:ident,
        preprocess_response: true,
        generic_type: $generic_type:tt,
        [$($bounds:tt)*],
        other_functions: {
            $($function_def: tt)*
        }
    ) => {
        impl <$generic_type: $($bounds)*>
            ConnectorIntegrationV2<
                $flow,
                $resource_common_data,
                $request,
                $response,
            > for $connector<$generic_type>
        {
            fn get_http_method(&self) -> common_utils::request::Method {
                common_utils::request::Method::$http_method_type
            }
            $($function_def)*
            $(
                macros::expand_default_functions!(
                    function: $function_name,
                    flow_name:$flow,
                    resource_common_data:$resource_common_data,
                    flow_request:$request,
                    flow_response:$response,
                );
            )*
            macros::expand_fn_get_request_body!(
                $connector,
                $curl_res,
                $flow,
                $resource_common_data,
                $request,
                $response
            );
            macros::expand_fn_handle_response!(
                $connector,
                $flow,
                $resource_common_data,
                $request,
                $response,
                preprocess_enabled
            );
        }
    };

    // Version with Dynamic content type selection
    (
        connector_default_implementations: [$($function_name:ident), *],
        connector: $connector:ident,
        curl_request: Dynamic($curl_req:ty),
        curl_response: $curl_res:ty,
        flow_name: $flow:ident,
        resource_common_data:$resource_common_data:ty,
        flow_request: $request:ty,
        flow_response: $response:ty,
        http_method: $http_method_type:ident,
        generic_type: $generic_type:tt,
        [$($bounds:tt)*],
        other_functions: {
            $($function_def: tt)*
        }
    ) => {
        impl<$generic_type: $($bounds)*>
            ConnectorIntegrationV2<
                $flow,
                $resource_common_data,
                $request,
                $response,
            > for $connector<$generic_type>
        {
            fn get_http_method(&self) -> common_utils::request::Method {
                common_utils::request::Method::$http_method_type
            }
            $($function_def)*
            $(
                macros::expand_default_functions!(
                    function: $function_name,
                    flow_name:$flow,
                    resource_common_data:$resource_common_data,
                    flow_request:$request,
                    flow_response:$response,
                );
            )*
            macros::expand_fn_get_request_body!(
                $connector,
                $curl_req,
                Dynamic,
                $curl_res,
                $flow,
                $resource_common_data,
                $request,
                $response
            );
            macros::expand_fn_handle_response!(
                $connector,
                $flow,
                $resource_common_data,
                $request,
                $response,
                no_preprocess
            );
        }
    };

    //Version without preprocess_response parameter (defaults to false)
    (
        connector_default_implementations: [$($function_name:ident), *],
        connector: $connector:ident,
        curl_request: $content_type:ident($curl_req:ty),
        curl_response: $curl_res:ty,
        flow_name: $flow:ident,
        resource_common_data:$resource_common_data:ty,
        flow_request: $request:ty,
        flow_response: $response:ty,
        http_method: $http_method_type:ident,
        generic_type: $generic_type:tt,
        [$($bounds:tt)*],
        other_functions: {
            $($function_def: tt)*
        }
    ) => {
        impl<$generic_type: $($bounds)*>
            ConnectorIntegrationV2<
                $flow,
                $resource_common_data,
                $request,
                $response,
            > for $connector<$generic_type>
        {
            fn get_http_method(&self) -> common_utils::request::Method {
                common_utils::request::Method::$http_method_type
            }
            $($function_def)*
            $(
                macros::expand_default_functions!(
                    function: $function_name,
                    flow_name:$flow,
                    resource_common_data:$resource_common_data,
                    flow_request:$request,
                    flow_response:$response,
                );
            )*
            macros::expand_fn_get_request_body!(
                $connector,
                $curl_req,
                $content_type,
                $curl_res,
                $flow,
                $resource_common_data,
                $request,
                $response
            );
            macros::expand_fn_handle_response!(
                $connector,
                $flow,
                $resource_common_data,
                $request,
                $response,
                no_preprocess
            );
        }
    };
    (
        connector_default_implementations: [$($function_name:ident), *],
        connector: $connector:ident,
        curl_response: $curl_res:ty,
        flow_name: $flow:ident,
        resource_common_data:$resource_common_data:ty,
        flow_request: $request:ident,
        flow_response: $response:ty,
        http_method: $http_method_type:ident,
        generic_type: $generic_type:tt,
        [$($bounds:tt)*],
        other_functions: {
            $($function_def: tt)*
        }
    ) => {
        impl<$generic_type: $($bounds)*>
            ConnectorIntegrationV2<
                $flow,
                $resource_common_data,
                $request,
                $response,
            > for $connector<$generic_type>
        {
            fn get_http_method(&self) -> common_utils::request::Method {
                common_utils::request::Method::$http_method_type
            }
            $($function_def)*
            $(
                macros::expand_default_functions!(
                    function: $function_name,
                    flow_name:$flow,
                    resource_common_data:$resource_common_data,
                    flow_request:$request,
                    flow_response:$response,
                );
            )*
            macros::expand_fn_get_request_body!(
                $connector,
                $curl_res,
                $flow,
                $resource_common_data,
                $request,
                $response
            );
            macros::expand_fn_handle_response!(
                $connector,
                $flow,
                $resource_common_data,
                $request,
                $response,
                no_preprocess
            );
        }
    };
    (
        connector_default_implementations: [$($function_name:ident), *],
        connector: $connector:ident,
        curl_response: $curl_res:ty,
        flow_name: $flow:ident,
        resource_common_data:$resource_common_data:ty,
        flow_request: $request:ty,
        flow_response: $response:ty,
        http_method: $http_method_type:ident,
        preprocess_response: $preprocess_response: expr,
        generic_type: $generic_type:tt,
        [$($bounds:tt)*],
        other_functions: {
            $($function_def: tt)*
        }
    ) => {
        impl<$generic_type: $($bounds)*>
            ConnectorIntegrationV2<
                $flow,
                $resource_common_data,
                $request,
                $response,
            > for $connector<$generic_type>
        {
            fn get_http_method(&self) -> common_utils::request::Method {
                common_utils::request::Method::$http_method_type
            }
            $($function_def)*
            $(
                macros::expand_default_functions!(
                    function: $function_name,
                    flow_name:$flow,
                    resource_common_data:$resource_common_data,
                    flow_request:$request,
                    flow_response:$response,
                );
            )*
            macros::expand_fn_get_request_body!(
                $connector,
                $curl_res,
                $flow,
                $resource_common_data,
                $request,
                $response
            );
            macros::expand_fn_handle_response!(
                $connector,
                $flow,
                $resource_common_data,
                $request,
                $response,
                preprocess_enabled
            );
        }
    };
}
pub(crate) use macro_connector_implementation;

macro_rules! impl_templating {

    (
        connector: $connector: ident,
        curl_request: $curl_req: ident,
        curl_response: $curl_res: ident,
        router_data: $router_data: ty,
        generic_type: $generic_type: tt,
    ) => {
        paste::paste!{
            pub struct [<$curl_req Templating>];
            pub struct [<$curl_res Templating>];

            impl<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> BridgeRequestResponse for Bridge<[<$curl_req Templating>], [<$curl_res Templating>], $generic_type>{
                type RequestBody = $curl_req;
                type ResponseBody = $curl_res;
                type ConnectorInputData = [<$connector RouterData>]<$router_data, $generic_type>;
            }
        }
    };
    (
        connector: $connector: ident,
        curl_response: $curl_res: ident,
        router_data: $router_data: ty,
        generic_type: $generic_type:tt,
    ) => {
        paste::paste!{
            pub struct [<$curl_res Templating>];

            impl<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> BridgeRequestResponse for Bridge<NoRequestBodyTemplating, [<$curl_res Templating>], $generic_type> {
                type RequestBody = NoRequestBody;
                type ResponseBody = $curl_res;
                type ConnectorInputData = [<$connector RouterData>]<$router_data, $generic_type>;
            }
        }
    };
}
pub(crate) use impl_templating;

macro_rules! impl_templating_mixed {
    // Pattern for generic request types like AdyenPaymentRequest<T>
    (
        connector: $connector: ident,
        curl_request: $base_req: ident<$req_generic: ident>,
        curl_response: $curl_res: ident,
        router_data: $router_data: ty,
        generic_type: $generic_type: tt,
    ) => {
        paste::paste!{
            pub struct [<$base_req Templating>];
            pub struct [<$curl_res Templating>];

            impl<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> BridgeRequestResponse for Bridge<[<$base_req Templating>], [<$curl_res Templating>], $generic_type>{
                type RequestBody = $base_req<$generic_type>;
                type ResponseBody = $curl_res;
                type ConnectorInputData = [<$connector RouterData>]<$router_data, $generic_type>;
            }
        }
    };

    // Pattern for non-generic request types like AdyenRedirectRequest
    (
        connector: $connector: ident,
        curl_request: $base_req: ident,
        curl_response: $curl_res: ident,
        router_data: $router_data: ty,
        generic_type: $generic_type: tt,
    ) => {
        paste::paste!{
            pub struct [<$base_req Templating>];
            pub struct [<$curl_res Templating>];

            impl<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> BridgeRequestResponse for Bridge<[<$base_req Templating>], [<$curl_res Templating>], $generic_type>{
                type RequestBody = $base_req;
                type ResponseBody = $curl_res;
                type ConnectorInputData = [<$connector RouterData>]<$router_data, $generic_type>;
            }
        }
    };

    // Pattern for generic request with XML response parsing
    (
        connector: $connector: ident,
        curl_request: $base_req: ident<$req_generic: ident>,
        curl_response: $curl_res: ident,
        router_data: $router_data: ty,
        generic_type: $generic_type: tt,
        response_format: xml,
    ) => {
        paste::paste!{
            pub struct [<$base_req Templating>];
            pub struct [<$curl_res Templating>];

            impl<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> BridgeRequestResponse for Bridge<[<$base_req Templating>], [<$curl_res Templating>], $generic_type>{
                type RequestBody = $base_req<$generic_type>;
                type ResponseBody = $curl_res;
                type ConnectorInputData = [<$connector RouterData>]<$router_data, $generic_type>;

                fn response(
                    &self,
                    bytes: bytes::Bytes,
                    status_code: u16,
                ) -> CustomResult<Self::ResponseBody, domain_types::errors::ConnectorError> {
                    use common_utils::ext_traits::XmlExt;
                    use error_stack::ResultExt;

                    if bytes.is_empty() {
                        return Err(
                            crate::utils::response_handling_fail_for_connector(status_code, "macros")
                                .into(),
                        );
                    }

                    let response_str = String::from_utf8(bytes.to_vec())
                        .change_context(
                            crate::utils::response_handling_fail_for_connector(status_code, "macros"),
                        )
                        .attach_printable("Failed to convert response bytes to UTF-8 string")?;

                    response_str
                        .as_str()
                        .parse_xml::<Self::ResponseBody>()
                        .change_context(
                            crate::utils::response_handling_fail_for_connector(status_code, "macros"),
                        )
                        .attach_printable("Failed to parse XML response")
                }
            }
        }
    };

    // Pattern for non-generic request with XML response parsing
    (
        connector: $connector: ident,
        curl_request: $base_req: ident,
        curl_response: $curl_res: ident,
        router_data: $router_data: ty,
        generic_type: $generic_type: tt,
        response_format: xml,
    ) => {
        paste::paste!{
            pub struct [<$base_req Templating>];
            pub struct [<$curl_res Templating>];

            impl<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> BridgeRequestResponse for Bridge<[<$base_req Templating>], [<$curl_res Templating>], $generic_type>{
                type RequestBody = $base_req;
                type ResponseBody = $curl_res;
                type ConnectorInputData = [<$connector RouterData>]<$router_data, $generic_type>;

                fn response(
                    &self,
                    bytes: bytes::Bytes,
                    status_code: u16,
                ) -> CustomResult<Self::ResponseBody, domain_types::errors::ConnectorError> {
                    use common_utils::ext_traits::XmlExt;
                    use error_stack::ResultExt;

                    if bytes.is_empty() {
                        return Err(
                            crate::utils::response_handling_fail_for_connector(status_code, "macros")
                                .into(),
                        );
                    }

                    let response_str = String::from_utf8(bytes.to_vec())
                        .change_context(
                            crate::utils::response_handling_fail_for_connector(status_code, "macros"),
                        )
                        .attach_printable("Failed to convert response bytes to UTF-8 string")?;

                    response_str
                        .as_str()
                        .parse_xml::<Self::ResponseBody>()
                        .change_context(
                            crate::utils::response_handling_fail_for_connector(status_code, "macros"),
                        )
                        .attach_printable("Failed to parse XML response")
                }
            }
        }
    };
}
pub(crate) use impl_templating_mixed;

macro_rules! resolve_request_body_type {
    // Generic type like AdyenPaymentRequest<T>
    ($base_req: ident<$req_generic: ident>, $generic_type: tt) => {
        $base_req<$generic_type>
    };
    // Non-generic type like AdyenRedirectRequest
    ($base_req: ident, $generic_type: tt) => {
        $base_req
    };
}
pub(crate) use resolve_request_body_type;

macro_rules! resolve_templating_type {
    // Generic type like AdyenPaymentRequest<T>
    ($base_req: ident<$req_generic: ident>) => {
        paste::paste! { [<$base_req Templating>] }
    };
    // Non-generic type like AdyenRedirectRequest
    ($base_req: ident) => {
        paste::paste! { [<$base_req Templating>] }
    };
}
pub(crate) use resolve_templating_type;

macro_rules! expand_connector_input_data {
    ($connector: ident, $generics: tt) => {
        paste::paste! {
            pub struct [<$connector RouterData>]<RD: FlowTypes, $generics: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> {
                pub connector: $connector<$generics>,
                pub router_data: RD
}
            impl<RD: FlowTypes, $generics: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> FlowTypes for [<$connector RouterData>]<RD, $generics> { //here too
                type Flow = RD::Flow;
                type FlowCommonData = RD::FlowCommonData;
                type Request = RD::Request;
                type Response = RD::Response;
            }
        }
    };
}
pub(crate) use expand_connector_input_data;

macro_rules! create_all_prerequisites {
    (
        connector_name: $connector: ident,
        generic_type: $generic_type:tt,
        api: [
            $(
                (
                    flow: $flow_name: ident,
                    $(request_body: $flow_request: ident $(<$generic_param: ident>)?,)?
                    response_body: $flow_response: ident,
                    $(response_format: $response_format:ident,)?
                    router_data: $router_data_type: ty,
                )
            ),*
        ],
        amount_converters: [
            $($converter_name:ident : $amount_unit:ty),*
        ],
        member_functions: {
            $($function_def: tt)*
        }
    ) => {
        crate::connectors::macros::expand_imports!();
        crate::connectors::macros::expand_connector_input_data!($connector, $generic_type);
        $(
            crate::connectors::macros::create_all_prerequisites_impl_templating!(
                connector: $connector,
                $(request_body: $flow_request $(<$generic_param>)?,)?
                response_body: $flow_response,
                $(response_format: $response_format,)?
                router_data: $router_data_type,
                generic_type: $generic_type,
            );
        )*
        paste::paste! {
            pub struct $connector<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> {
                $(
                    pub $converter_name: &'static (dyn common_utils::types::AmountConvertor<Output = $amount_unit> + Sync),
                )*
                $(
                    [<$flow_name:snake>]: &'static dyn BridgeRequestResponse<
                        RequestBody = crate::connectors::macros::create_all_prerequisites_resolve_request_body_type!($(request_body: $flow_request $(<$generic_param>)?,)? generic_type: $generic_type),
                        ResponseBody = $flow_response,
                        ConnectorInputData = [<$connector RouterData>]<$router_data_type, $generic_type>,
                    >,
                )*
                pub _marker: std::marker::PhantomData<$generic_type>,
            }

            impl<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize> Clone for $connector<$generic_type> {
                fn clone(&self) -> Self {
                    Self {
                        $(
                            $converter_name: self.$converter_name,
                        )*
                        $(
                            [<$flow_name:snake>]: self.[<$flow_name:snake>],
                        )*
                        _marker: self._marker,
                    }
                }
            }

            impl<$generic_type: PaymentMethodDataTypes + std::fmt::Debug + std::marker::Sync + std::marker::Send + 'static + serde::Serialize>  $connector<$generic_type> {
                pub const fn new() -> &'static Self {
                    &Self{
                        $(
                            $converter_name: &common_utils::types::[<$amount_unit ForConnector>],
                        )*
                        $(
                            [<$flow_name:snake>]: &Bridge::<
                                    crate::connectors::macros::create_all_prerequisites_resolve_templating_type!($(request_body: $flow_request $(<$generic_param>)?,)?),
                                    [<$flow_response Templating>], $generic_type
                                >(PhantomData),
                        )*
                        _marker: std::marker::PhantomData,
                    }
                }
                $($function_def)*
            }
        }
    };
}
pub(crate) use create_all_prerequisites;

macro_rules! create_all_prerequisites_impl_templating {
    // Pattern with request body and XML response format
    (
        connector: $connector: ident,
        request_body: $flow_request: ident $(<$generic_param: ident>)?,
        response_body: $flow_response: ident,
        response_format: xml,
        router_data: $router_data_type: ty,
        generic_type: $generic_type: tt,
    ) => {
        crate::connectors::macros::impl_templating_mixed!(
            connector: $connector,
            curl_request: $flow_request $(<$generic_param>)?,
            curl_response: $flow_response,
            router_data: $router_data_type,
            generic_type: $generic_type,
            response_format: xml,
        );
    };

    // Pattern with request body (default JSON response format)
    (
        connector: $connector: ident,
        request_body: $flow_request: ident $(<$generic_param: ident>)?,
        response_body: $flow_response: ident,
        router_data: $router_data_type: ty,
        generic_type: $generic_type: tt,
    ) => {
        crate::connectors::macros::impl_templating_mixed!(
            connector: $connector,
            curl_request: $flow_request $(<$generic_param>)?,
            curl_response: $flow_response,
            router_data: $router_data_type,
            generic_type: $generic_type,
        );
    };

    // Pattern without request body
    (
        connector: $connector: ident,
        response_body: $flow_response: ident,
        router_data: $router_data_type: ty,
        generic_type: $generic_type: tt,
    ) => {
        crate::connectors::macros::impl_templating!(
            connector: $connector,
            curl_response: $flow_response,
            router_data: $router_data_type,
            generic_type: $generic_type,
        );
    };
}
pub(crate) use create_all_prerequisites_impl_templating;

macro_rules! create_all_prerequisites_resolve_request_body_type {
    // Pattern with request body
    (
        request_body: $flow_request: ident $(<$generic_param: ident>)?,
        generic_type: $generic_type: tt
    ) => {
        crate::connectors::macros::resolve_request_body_type!($flow_request $(<$generic_param>)?, $generic_type)
    };

    // Pattern without request body
    (
        generic_type: $generic_type: tt
    ) => {
        NoRequestBody
    };
}
pub(crate) use create_all_prerequisites_resolve_request_body_type;

macro_rules! create_all_prerequisites_resolve_templating_type {
    // Pattern with request body
    (
        request_body: $flow_request: ident $(<$generic_param: ident>)?,
    ) => {
        crate::connectors::macros::resolve_templating_type!($flow_request $(<$generic_param>)?)
    };

    // Pattern without request body
    () => {
        NoRequestBodyTemplating
    };
}
pub(crate) use create_all_prerequisites_resolve_templating_type;

macro_rules! expand_imports {
    () => {
        #[allow(unused_imports)]
        use std::marker::PhantomData;

        #[allow(unused_imports)]
        use crate::connectors::macros::{
            Bridge, BridgeRequestResponse, FlowTypes, GetFormData, NoRequestBody,
            NoRequestBodyTemplating,
        };
        #[allow(unused_imports)]
        mod macro_types {
            // pub(super) use domain_models::{
            //     AuthenticationInitiation, Confirmation, PostAuthenticationSync, PreAuthentication,
            // };
            pub(super) use common_utils::{errors::CustomResult, events, request::RequestContent};
            pub(super) use domain_types::{
                errors::{ConnectorError, IntegrationError},
                router_data::{ConnectorSpecificConfig, ErrorResponse},
                router_data_v2::RouterDataV2,
                router_response_types::Response,
            };
            pub(super) use hyperswitch_masking::Maskable;

            pub(super) use crate::types::*;
        }
    };
}
pub(crate) use expand_imports;

macro_rules! create_amount_converter_wrapper {
    (connector_name: $connector_name:ident, amount_type: $amount_type:ty) => {
        paste::paste! {
            #[derive(Default, Debug, Clone, Copy, PartialEq)]
            pub struct [<$connector_name AmountConvertor>];

            impl [<$connector_name AmountConvertor>] {
                pub fn convert(
                    amount: common_utils::types::MinorUnit,
                    currency: common_enums::Currency,
                ) -> Result<
                    common_utils::types::$amount_type,
                    error_stack::Report<domain_types::errors::IntegrationError>,
                > {
                    domain_types::utils::convert_amount(
                        &common_utils::types::[<$amount_type ForConnector>],
                        amount,
                        currency,
                    ).change_context(domain_types::errors::IntegrationError::InvalidDataFormat {
                        field_name: "amount",
                        context: Default::default()
                  })
                }

                /// Convert connector amount back to MinorUnit.
                ///
                /// Returns generic ParsingError - caller should change_context appropriately:
                /// ```
                /// // In response transformation:
                /// let amount = Convertor::convert_back(response.amount, currency)
                ///     .change_context(crate::utils::response_handling_fail_for_connector(http_code, "macros"))?;
                pub fn convert_back(
                    amount: common_utils::types::$amount_type,
                    currency: common_enums::Currency,
                ) -> Result<
                    common_utils::types::MinorUnit,
                    error_stack::Report<common_utils::errors::ParsingError>,
                > {
                    domain_types::utils::convert_back_amount_to_minor_units(
                        &common_utils::types::[<$amount_type ForConnector>],
                        amount,
                        currency,
                    )
                }
            }
        }
    };
}

pub(crate) use create_amount_converter_wrapper;

/// Generates default (empty/no-op) payout trait implementations for a connector.
///
/// This macro is the **public entry point** for registering a connector struct with all
/// payout-related flows. It works in tandem with [`expand_payout_implementation!`], which
/// does the actual `impl` generation for each individual flow.
///
/// # How it works
///
/// The macro uses a **recursive list-peeling** pattern with three arms:
///
/// 1. **Default arm (no `payout_flows` specified)** – Expands the full list of all eight
///    payout flows (`PayoutCreate`, `PayoutTransfer`, `PayoutGet`, `PayoutVoid`,
///    `PayoutStage`, `PayoutCreateLink`, `PayoutCreateRecipient`,
///    `PayoutEnrollDisburseAccount`) and re-invokes itself with that list.
///
/// 2. **Recursive arm (`payout_flows: [head, tail…]`)** – Peels the first flow off the
///    list, delegates it to [`expand_payout_implementation!`] to emit the trait impls for
///    that single flow, then recurses on the remaining flows.
///
/// 3. **Base-case arm (`payout_flows: []`)** – Empty list; terminates the recursion.
macro_rules! macro_connector_payout_implementation {
    // Arm 1: Default – no explicit payout_flows list provided.
    // Supplies the full set of all eight payout flows and re-invokes itself.
    (
        connector: $connector: ident,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        $crate::connectors::macros::macro_connector_payout_implementation!(
            connector: $connector,
            generic_type: $generic_type,
            [ $($bounds)* ],
            payout_flows: [
                PayoutCreate,
                PayoutTransfer,
                PayoutGet,
                PayoutVoid,
                PayoutStage,
                PayoutCreateLink,
                PayoutCreateRecipient,
                PayoutEnrollDisburseAccount
            ]
        );
    };

    // Arm 2: Recursive – peel the first flow (`$flow`) from the list, generate its impls
    // via `expand_payout_implementation!`, then recurse on the remaining flows (`$rest`).
    (
        connector: $connector: ident,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ],
        payout_flows: [ $flow: ident $(, $rest: ident)* ]
    ) => {
        $crate::connectors::macros::expand_payout_implementation!(
            connector: $connector,
            flow: $flow,
            generic_type: $generic_type,
            [ $($bounds)* ]
        );
        $crate::connectors::macros::macro_connector_payout_implementation!(
            connector: $connector,
            generic_type: $generic_type,
            [ $($bounds)* ],
            payout_flows: [ $($rest),* ]
        );
    };

    // Arm 3: Base case – empty flow list; terminate recursion.
    (
        connector: $connector: ident,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ],
        payout_flows: []
    ) => {};

}
pub(crate) use macro_connector_payout_implementation;

/// Emits the concrete trait implementations for a **single** payout flow on a connector.
///
/// This macro is the **internal workhorse** called by [`macro_connector_payout_implementation!`].
/// It pattern-matches on the flow identifier and generates two trait implementations for
/// the connector:
///
macro_rules! expand_payout_implementation {
    (
        connector: $connector: ident,
        flow: PayoutCreate,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        impl<$generic_type: $($bounds)*> ::interfaces::connector_types::PayoutCreateV2 for $connector<$generic_type> {}
        impl<$generic_type: $($bounds)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                ::domain_types::connector_flow::PayoutCreate,
                ::domain_types::payouts::payouts_types::PayoutFlowData,
                ::domain_types::payouts::payouts_types::PayoutCreateRequest,
                ::domain_types::payouts::payouts_types::PayoutCreateResponse,
            > for $connector<$generic_type>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    ::domain_types::connector_flow::PayoutCreate,
                    ::domain_types::payouts::payouts_types::PayoutFlowData,
                    ::domain_types::payouts::payouts_types::PayoutCreateRequest,
                    ::domain_types::payouts::payouts_types::PayoutCreateResponse,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    "payout_create",
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
    (
        connector: $connector: ident,
        flow: PayoutTransfer,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        impl<$generic_type: $($bounds)*> ::interfaces::connector_types::PayoutTransferV2 for $connector<$generic_type> {}
        impl<$generic_type: $($bounds)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                ::domain_types::connector_flow::PayoutTransfer,
                ::domain_types::payouts::payouts_types::PayoutFlowData,
                ::domain_types::payouts::payouts_types::PayoutTransferRequest,
                ::domain_types::payouts::payouts_types::PayoutTransferResponse,
            > for $connector<$generic_type>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    ::domain_types::connector_flow::PayoutTransfer,
                    ::domain_types::payouts::payouts_types::PayoutFlowData,
                    ::domain_types::payouts::payouts_types::PayoutTransferRequest,
                    ::domain_types::payouts::payouts_types::PayoutTransferResponse,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    "payout_transfer",
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
    (
        connector: $connector: ident,
        flow: PayoutGet,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        impl<$generic_type: $($bounds)*> ::interfaces::connector_types::PayoutGetV2 for $connector<$generic_type> {}
        impl<$generic_type: $($bounds)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                ::domain_types::connector_flow::PayoutGet,
                ::domain_types::payouts::payouts_types::PayoutFlowData,
                ::domain_types::payouts::payouts_types::PayoutGetRequest,
                ::domain_types::payouts::payouts_types::PayoutGetResponse,
            > for $connector<$generic_type>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    ::domain_types::connector_flow::PayoutGet,
                    ::domain_types::payouts::payouts_types::PayoutFlowData,
                    ::domain_types::payouts::payouts_types::PayoutGetRequest,
                    ::domain_types::payouts::payouts_types::PayoutGetResponse,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    "payout_get",
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
    (
        connector: $connector: ident,
        flow: PayoutVoid,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        impl<$generic_type: $($bounds)*> ::interfaces::connector_types::PayoutVoidV2 for $connector<$generic_type> {}
        impl<$generic_type: $($bounds)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                ::domain_types::connector_flow::PayoutVoid,
                ::domain_types::payouts::payouts_types::PayoutFlowData,
                ::domain_types::payouts::payouts_types::PayoutVoidRequest,
                ::domain_types::payouts::payouts_types::PayoutVoidResponse,
            > for $connector<$generic_type>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    ::domain_types::connector_flow::PayoutVoid,
                    ::domain_types::payouts::payouts_types::PayoutFlowData,
                    ::domain_types::payouts::payouts_types::PayoutVoidRequest,
                    ::domain_types::payouts::payouts_types::PayoutVoidResponse,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    "payout_void",
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
    (
        connector: $connector: ident,
        flow: PayoutStage,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        impl<$generic_type: $($bounds)*> ::interfaces::connector_types::PayoutStageV2 for $connector<$generic_type> {}
        impl<$generic_type: $($bounds)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                ::domain_types::connector_flow::PayoutStage,
                ::domain_types::payouts::payouts_types::PayoutFlowData,
                ::domain_types::payouts::payouts_types::PayoutStageRequest,
                ::domain_types::payouts::payouts_types::PayoutStageResponse,
            > for $connector<$generic_type>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    ::domain_types::connector_flow::PayoutStage,
                    ::domain_types::payouts::payouts_types::PayoutFlowData,
                    ::domain_types::payouts::payouts_types::PayoutStageRequest,
                    ::domain_types::payouts::payouts_types::PayoutStageResponse,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    "payout_stage",
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
    (
        connector: $connector: ident,
        flow: PayoutCreateLink,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        impl<$generic_type: $($bounds)*> ::interfaces::connector_types::PayoutCreateLinkV2 for $connector<$generic_type> {}
        impl<$generic_type: $($bounds)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                ::domain_types::connector_flow::PayoutCreateLink,
                ::domain_types::payouts::payouts_types::PayoutFlowData,
                ::domain_types::payouts::payouts_types::PayoutCreateLinkRequest,
                ::domain_types::payouts::payouts_types::PayoutCreateLinkResponse,
            > for $connector<$generic_type>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    ::domain_types::connector_flow::PayoutCreateLink,
                    ::domain_types::payouts::payouts_types::PayoutFlowData,
                    ::domain_types::payouts::payouts_types::PayoutCreateLinkRequest,
                    ::domain_types::payouts::payouts_types::PayoutCreateLinkResponse,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    "payout_create_link",
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
    (
        connector: $connector: ident,
        flow: PayoutCreateRecipient,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        impl<$generic_type: $($bounds)*> ::interfaces::connector_types::PayoutCreateRecipientV2 for $connector<$generic_type> {}
        impl<$generic_type: $($bounds)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                ::domain_types::connector_flow::PayoutCreateRecipient,
                ::domain_types::payouts::payouts_types::PayoutFlowData,
                ::domain_types::payouts::payouts_types::PayoutCreateRecipientRequest,
                ::domain_types::payouts::payouts_types::PayoutCreateRecipientResponse,
            > for $connector<$generic_type>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    ::domain_types::connector_flow::PayoutCreateRecipient,
                    ::domain_types::payouts::payouts_types::PayoutFlowData,
                    ::domain_types::payouts::payouts_types::PayoutCreateRecipientRequest,
                    ::domain_types::payouts::payouts_types::PayoutCreateRecipientResponse,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    "payout_create_recipient",
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
    (
        connector: $connector: ident,
        flow: PayoutEnrollDisburseAccount,
        generic_type: $generic_type:tt,
        [ $($bounds:tt)* ]
    ) => {
        impl<$generic_type: $($bounds)*> ::interfaces::connector_types::PayoutEnrollDisburseAccountV2 for $connector<$generic_type> {}
        impl<$generic_type: $($bounds)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                ::domain_types::connector_flow::PayoutEnrollDisburseAccount,
                ::domain_types::payouts::payouts_types::PayoutFlowData,
                ::domain_types::payouts::payouts_types::PayoutEnrollDisburseAccountRequest,
                ::domain_types::payouts::payouts_types::PayoutEnrollDisburseAccountResponse,
            > for $connector<$generic_type>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    ::domain_types::connector_flow::PayoutEnrollDisburseAccount,
                    ::domain_types::payouts::payouts_types::PayoutFlowData,
                    ::domain_types::payouts::payouts_types::PayoutEnrollDisburseAccountRequest,
                    ::domain_types::payouts::payouts_types::PayoutEnrollDisburseAccountResponse,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    "payout_enroll_disburse_account",
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
}
pub(crate) use expand_payout_implementation;

/// Generate stub `ConnectorIntegrationV2` impls for non-payout flows that the
/// connector either does not yet implement (`not_implemented`) or does not
/// support at all (`not_supported`).
///
/// Each entry in the lists is a flow identifier from
/// `domain_types::connector_flow`. The macro looks up the flow's full type
/// signature internally (see [`expand_flow_status_impl!`]) and emits one full
/// `impl ConnectorIntegrationV2<F, FCD, Req, Resp>` block whose `get_url`
/// returns `Err(IntegrationError::connector_flow_not_implemented(...).into())`
/// or `Err(IntegrationError::connector_flow_not_supported(...).into())`.
///
/// Mirrors the recursive list-peeling pattern used by
/// [`macro_connector_payout_implementation!`].
macro_rules! macro_connector_flow_status_impls {
    // ----- User-facing entry arms: both lists -----
    (
        connector: $connector: ident,
        generic_type: $g: tt,
        [ $($b:tt)* ],
        not_implemented: [ $($ni: ident),* $(,)? ],
        not_supported: [ $($ns: ident),* $(,)? ] $(,)?
    ) => {
        $crate::connectors::macros::macro_connector_flow_status_impls!(
            @peel status: not_implemented,
            connector: $connector,
            generic_type: $g,
            [ $($b)* ],
            flows: [ $($ni),* ]
        );
        $crate::connectors::macros::macro_connector_flow_status_impls!(
            @peel status: not_supported,
            connector: $connector,
            generic_type: $g,
            [ $($b)* ],
            flows: [ $($ns),* ]
        );
    };

    // ----- User-facing entry arms: only `not_implemented` -----
    (
        connector: $connector: ident,
        generic_type: $g: tt,
        [ $($b:tt)* ],
        not_implemented: [ $($ni: ident),* $(,)? ] $(,)?
    ) => {
        $crate::connectors::macros::macro_connector_flow_status_impls!(
            @peel status: not_implemented,
            connector: $connector,
            generic_type: $g,
            [ $($b)* ],
            flows: [ $($ni),* ]
        );
    };

    // ----- User-facing entry arms: only `not_supported` -----
    (
        connector: $connector: ident,
        generic_type: $g: tt,
        [ $($b:tt)* ],
        not_supported: [ $($ns: ident),* $(,)? ] $(,)?
    ) => {
        $crate::connectors::macros::macro_connector_flow_status_impls!(
            @peel status: not_supported,
            connector: $connector,
            generic_type: $g,
            [ $($b)* ],
            flows: [ $($ns),* ]
        );
    };

    // ----- Internal recursive peel: canonical entry, more to come -----
    (
        @peel status: $status: ident,
        connector: $connector: ident,
        generic_type: $g: tt,
        [ $($b:tt)* ],
        flows: [ $head: ident, $($tail: tt)* ]
    ) => {
        $crate::connectors::macros::expand_flow_status_impl!(
            connector: $connector,
            flow: $head,
            status: $status,
            generic_type: $g,
            [ $($b)* ]
        );
        $crate::connectors::macros::macro_connector_flow_status_impls!(
            @peel status: $status,
            connector: $connector,
            generic_type: $g,
            [ $($b)* ],
            flows: [ $($tail)* ]
        );
    };

    // ----- Internal recursive peel: canonical entry, last (optional trailing comma) -----
    (
        @peel status: $status: ident,
        connector: $connector: ident,
        generic_type: $g: tt,
        [ $($b:tt)* ],
        flows: [ $head: ident $(,)? ]
    ) => {
        $crate::connectors::macros::expand_flow_status_impl!(
            connector: $connector,
            flow: $head,
            status: $status,
            generic_type: $g,
            [ $($b)* ]
        );
    };

    // ----- Internal recursive peel: base case (empty list) -----
    (
        @peel status: $status: ident,
        connector: $connector: ident,
        generic_type: $g: tt,
        [ $($b:tt)* ],
        flows: []
    ) => {};
}
pub(crate) use macro_connector_flow_status_impls;

/// Look up a flow identifier's full type signature + marker trait, then emit
/// both a marker-trait impl and a stub `ConnectorIntegrationV2` impl.
///
/// One arm per non-payout flow in `domain_types::connector_flow`. Each arm:
///   1. Emits the connector's marker-trait impl (`impl<G: bounds> Marker[<G>] for $c<G> {}`)
///      so that hand-written one-liners at the top of every connector file can be removed.
///   2. Forwards `(flow_path, flow_name, flow_common_data, request, response)`
///      to [`flow_status_emit!`] which produces the `ConnectorIntegrationV2`
///      stub. The error name is the snake_case literal passed by the arm.
macro_rules! expand_flow_status_impl {
    // ---- PaymentFlowData family, non-generic markers ----
    (connector: $c:ident, flow: CreateOrder, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentOrderCreate for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::CreateOrder,
            flow_name: "create_order",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentCreateOrderData,
            response: ::domain_types::connector_types::PaymentCreateOrderResponse,
        );
    };
    (connector: $c:ident, flow: PSync, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentSyncV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::PSync,
            flow_name: "payment_sync",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentsSyncData,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: Void, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentVoidV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::Void,
            flow_name: "void",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentVoidData,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: Capture, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentCapture for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::Capture,
            flow_name: "capture",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentsCaptureData,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: VoidPC, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentVoidPostCaptureV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::VoidPC,
            flow_name: "void_post_capture",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentsCancelPostCaptureData,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: IncrementalAuthorization, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentIncrementalAuthorization for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::IncrementalAuthorization,
            flow_name: "incremental_authorization",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentsIncrementalAuthorizationData,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: CreateConnectorCustomer, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::CreateConnectorCustomer for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::CreateConnectorCustomer,
            flow_name: "create_connector_customer",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::ConnectorCustomerData,
            response: ::domain_types::connector_types::ConnectorCustomerResponse,
        );
    };
    (connector: $c:ident, flow: GetConnectorCustomer, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::GetConnectorCustomer for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::GetConnectorCustomer,
            flow_name: "get_connector_customer",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::ConnectorCustomerData,
            response: ::domain_types::connector_types::ConnectorCustomerResponse,
        );
    };
    (connector: $c:ident, flow: MandateRevoke, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::MandateRevokeV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::MandateRevoke,
            flow_name: "mandate_revoke",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::MandateRevokeRequestData,
            response: ::domain_types::connector_types::MandateRevokeResponseData,
        );
    };
    (connector: $c:ident, flow: ClientAuthenticationToken, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::ClientAuthentication for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::ClientAuthenticationToken,
            flow_name: "client_authentication_token",
            flow_common_data: ::domain_types::merchant_authentication_flow_data::MerchantAuthenticationFlowData,
            request: ::domain_types::connector_types::ClientAuthenticationTokenRequestData,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: ServerAuthenticationToken, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::ServerAuthentication for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::ServerAuthenticationToken,
            flow_name: "server_authentication_token",
            flow_common_data: ::domain_types::merchant_authentication_flow_data::MerchantAuthenticationFlowData,
            request: ::domain_types::connector_types::ServerAuthenticationTokenRequestData,
            response: ::domain_types::connector_types::ServerAuthenticationTokenResponseData,
        );
    };
    (connector: $c:ident, flow: ServerSessionAuthenticationToken, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::ServerSessionAuthentication for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::ServerSessionAuthenticationToken,
            flow_name: "server_session_authentication_token",
            flow_common_data: ::domain_types::merchant_authentication_flow_data::MerchantAuthenticationFlowData,
            request: ::domain_types::connector_types::ServerSessionAuthenticationTokenRequestData,
            response: ::domain_types::connector_types::ServerSessionAuthenticationTokenResponseData,
        );
    };

    // ---- PaymentFlowData family, generic-in-T markers ----
    (connector: $c:ident, flow: Authorize, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentAuthorizeV2<$g> for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::Authorize,
            flow_name: "authorize",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentsAuthorizeData<$g>,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: SetupMandate, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::SetupMandateV2<$g> for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::SetupMandate,
            flow_name: "setup_mandate",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::SetupMandateRequestData<$g>,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: RepeatPayment, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::RepeatPaymentV2<$g> for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::RepeatPayment,
            flow_name: "repeat_payment",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::RepeatPaymentData<$g>,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: PaymentMethodToken, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentTokenV2<$g> for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::PaymentMethodToken,
            flow_name: "payment_method_token",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentMethodTokenizationData<$g>,
            response: ::domain_types::connector_types::PaymentMethodTokenResponse,
        );
    };
    (connector: $c:ident, flow: PreAuthenticate, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentPreAuthenticateV2<$g> for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::PreAuthenticate,
            flow_name: "pre_authenticate",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentsPreAuthenticateData<$g>,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: Authenticate, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentAuthenticateV2<$g> for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::Authenticate,
            flow_name: "authenticate",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentsAuthenticateData<$g>,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };
    (connector: $c:ident, flow: PostAuthenticate, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentPostAuthenticateV2<$g> for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::PostAuthenticate,
            flow_name: "post_authenticate",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentsPostAuthenticateData<$g>,
            response: ::domain_types::connector_types::PaymentsResponseData,
        );
    };

    // ---- PaymentMethodEligibility ----
    (connector: $c:ident, flow: PaymentMethodEligibility, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::PaymentMethodEligibilityV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::PaymentMethodEligibility,
            flow_name: "eligibility",
            flow_common_data: ::domain_types::connector_types::PaymentFlowData,
            request: ::domain_types::connector_types::PaymentMethodEligibilityData,
            response: ::domain_types::connector_types::PaymentMethodEligibilityResponse,
        );
    };

    // ---- Refund family ----
    (connector: $c:ident, flow: Refund, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::RefundV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::Refund,
            flow_name: "refund",
            flow_common_data: ::domain_types::connector_types::RefundFlowData,
            request: ::domain_types::connector_types::RefundsData,
            response: ::domain_types::connector_types::RefundsResponseData,
        );
    };
    (connector: $c:ident, flow: VoidPostRefund, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::RefundVoidPostRefundV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::VoidPostRefund,
            flow_name: "void_post_refund",
            flow_common_data: ::domain_types::connector_types::RefundFlowData,
            request: ::domain_types::connector_types::RefundVoidPostRefundData,
            response: ::domain_types::connector_types::RefundsResponseData,
        );
    };
    (connector: $c:ident, flow: RSync, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::RefundSyncV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::RSync,
            flow_name: "refund_sync",
            flow_common_data: ::domain_types::connector_types::RefundFlowData,
            request: ::domain_types::connector_types::RefundSyncData,
            response: ::domain_types::connector_types::RefundsResponseData,
        );
    };

    // ---- Dispute family ----
    (connector: $c:ident, flow: Accept, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::AcceptDispute for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::Accept,
            flow_name: "accept_dispute",
            flow_common_data: ::domain_types::connector_types::DisputeFlowData,
            request: ::domain_types::connector_types::AcceptDisputeData,
            response: ::domain_types::connector_types::DisputeResponseData,
        );
    };
    (connector: $c:ident, flow: SubmitEvidence, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::SubmitEvidenceV2 for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::SubmitEvidence,
            flow_name: "submit_evidence",
            flow_common_data: ::domain_types::connector_types::DisputeFlowData,
            request: ::domain_types::connector_types::SubmitEvidenceData,
            response: ::domain_types::connector_types::DisputeResponseData,
        );
    };
    (connector: $c:ident, flow: DefendDispute, status: $st:ident, generic_type: $g:tt, [$($b:tt)*]) => {
        impl<$g: $($b)*> ::interfaces::connector_types::DisputeDefend for $c<$g> {}
        $crate::connectors::macros::flow_status_emit!(
            connector: $c, status: $st, generic_type: $g, [$($b)*],
            flow: ::domain_types::connector_flow::DefendDispute,
            flow_name: "defend_dispute",
            flow_common_data: ::domain_types::connector_types::DisputeFlowData,
            request: ::domain_types::connector_types::DisputeDefendData,
            response: ::domain_types::connector_types::DisputeResponseData,
        );
    };
}
pub(crate) use expand_flow_status_impl;

/// Emit a stub `ConnectorIntegrationV2` impl whose `get_url` returns
/// `Err(IntegrationError::connector_flow_not_implemented(...).into())` or
/// `Err(IntegrationError::connector_flow_not_supported(...).into())`. The
/// flow name (for the error message) is passed as a string literal by the
/// calling [`expand_flow_status_impl!`] arm.
///
/// The marker-trait impl pairing for stubbed flows is emitted by the
/// per-flow arms in [`expand_flow_status_impl!`] before they call this macro.
macro_rules! flow_status_emit {
    (
        connector: $c:ident,
        status: not_implemented,
        generic_type: $g:tt,
        [$($b:tt)*],
        flow: $flow:path,
        flow_name: $name:literal,
        flow_common_data: $fcd:path,
        request: $req:ty,
        response: $resp:ty $(,)?
    ) => {
        impl<$g: $($b)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<$flow, $fcd, $req, $resp>
            for $c<$g>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<$flow, $fcd, $req, $resp>,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    $name,
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
    (
        connector: $c:ident,
        status: not_supported,
        generic_type: $g:tt,
        [$($b:tt)*],
        flow: $flow:path,
        flow_name: $name:literal,
        flow_common_data: $fcd:path,
        request: $req:ty,
        response: $resp:ty $(,)?
    ) => {
        impl<$g: $($b)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<$flow, $fcd, $req, $resp>
            for $c<$g>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<$flow, $fcd, $req, $resp>,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_supported(
                    ::interfaces::api::ConnectorCommon::id(self),
                    $name,
                    ::domain_types::errors::IntegrationErrorContext::default(),
                ).into())
            }
        }
    };
}
pub(crate) use flow_status_emit;

/// Emit a `ConnectorIntegrationV2` stub for an FRM flow that a connector does
/// not implement, so the FRM service surfaces a clear "flow not implemented"
/// error instead of the connector failing to compile. All FRM flows share
/// [`FrmFlowData`] as their common data, so this only needs the connector type
/// (with its generic parameter + bounds) and the flow's request/response types.
/// Generic over the connector, so any FRM connector can reuse it.
macro_rules! frm_flow_not_implemented {
    (
        connector: $c:ident,
        generic_type: $g:tt,
        [$($b:tt)*],
        flow: $flow:ty,
        request: $req:ty,
        response: $resp:ty,
        flow_name: $name:literal $(,)?
    ) => {
        impl<$g: $($b)*>
            ::interfaces::connector_integration_v2::ConnectorIntegrationV2<
                $flow,
                ::domain_types::frm::frm_types::FrmFlowData,
                $req,
                $resp,
            > for $c<$g>
        {
            fn get_url(
                &self,
                _req: &::domain_types::router_data_v2::RouterDataV2<
                    $flow,
                    ::domain_types::frm::frm_types::FrmFlowData,
                    $req,
                    $resp,
                >,
            ) -> ::common_utils::CustomResult<String, ::domain_types::errors::IntegrationError> {
                Err(::domain_types::errors::IntegrationError::connector_flow_not_implemented(
                    ::interfaces::api::ConnectorCommon::id(self),
                    $name,
                    ::domain_types::errors::IntegrationErrorContext {
                        additional_context: Some(format!(
                            "{} does not implement the `{}` FRM flow",
                            ::interfaces::api::ConnectorCommon::id(self),
                            $name
                        )),
                        suggested_action: Some(format!(
                            "Do not route the `{}` FRM flow to this connector",
                            $name
                        )),
                        doc_url: None,
                    },
                )
                .into())
            }
        }
    };
}
pub(crate) use frm_flow_not_implemented;
