// Struct: CustomerBankAccountResponse
// File: crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CustomerBankAccountResponse


// File: crates/hyperswitch_connectors/src/connectors/custombilling.rs
// Module: hyperswitch_connectors
// Public functions: 1
// Public structs: 1

pub mod transformers;

use common_utils::{
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector},
};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{PaymentsResponseData, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks,
};
use transformers as custombilling;

use crate::{constants::headers, types::ResponseRouterData, utils};

#[derive(Clone)]
pub struct Custombilling {
    amount_converter: &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
}

impl Custombilling {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &StringMinorUnitForConnector,
        }
    }
}

impl api::Payment for Custombilling {}
impl api::PaymentSession for Custombilling {}
impl api::ConnectorAccessToken for Custombilling {}
impl api::MandateSetup for Custombilling {}
impl api::PaymentAuthorize for Custombilling {}
impl api::PaymentSync for Custombilling {}
impl api::PaymentCapture for Custombilling {}
impl api::PaymentVoid for Custombilling {}
impl api::Refund for Custombilling {}
impl api::RefundExecute for Custombilling {}
impl api::RefundSync for Custombilling {}
impl api::PaymentToken for Custombilling {}

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Custombilling
{
    // Not Implemented (R)
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Custombilling
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let mut header = vec![(
            headers::CONTENT_TYPE.to_string(),
            self.get_content_type().to_string().into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }
}

impl ConnectorCommon for Custombilling {
    fn id(&self) -> &'static str {
        "custombilling"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Minor
        //    TODO! Check connector documentation, on which unit they are processing the currency.
        //    If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor,
        //    if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

    fn base_url<'a>(&self, _connectors: &'a Connectors) -> &'a str {
        ""
    }

    fn get_auth_header(
        &self,
        _auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: custombilling::CustombillingErrorResponse = res
            .response
            .parse_struct("CustombillingErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.code,
            message: response.message,
            reason: response.reason,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorValidation for Custombilling {
    //TODO: implement functions when support enabled
}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Custombilling {
    //TODO: implement sessions flow
}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Custombilling {}

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
    for Custombilling
{
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData>
    for Custombilling
{
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;

        let connector_router_data = custombilling::CustombillingRouterData::from((amount, req));
        let connector_req =
            custombilling::CustombillingPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(types::PaymentsAuthorizeType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(types::PaymentsAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: custombilling::CustombillingPaymentsResponse = res
            .response
            .parse_struct("Custombilling PaymentsAuthorizeResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Custombilling {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: custombilling::CustombillingPaymentsResponse = res
            .response
            .parse_struct("custombilling PaymentsSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Custombilling {
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn get_request_body(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
    }

    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsCaptureType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(types::PaymentsCaptureType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: custombilling::CustombillingPaymentsResponse = res
            .response
            .parse_struct("Custombilling PaymentsCaptureResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Custombilling {}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Custombilling {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let refund_amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;

        let connector_router_data =
            custombilling::CustombillingRouterData::from((refund_amount, req));
        let connector_req =
            custombilling::CustombillingRefundRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::RefundExecuteType::get_headers(
                self, req, connectors,
            )?)
            .set_body(types::RefundExecuteType::get_request_body(
                self, req, connectors,
            )?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        let response: custombilling::RefundResponse = res
            .response
            .parse_struct("custombilling RefundResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Custombilling {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &RefundSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn build_request(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&types::RefundSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::RefundSyncType::get_headers(self, req, connectors)?)
                .set_body(types::RefundSyncType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: custombilling::RefundResponse = res
            .response
            .parse_struct("custombilling RefundSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Custombilling {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_resource_object(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}

impl ConnectorSpecifications for Custombilling {}


// Struct: AffirmCancelRequest
// File: crates/hyperswitch_connectors/src/connectors/affirm/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AffirmCancelRequest


// Function: payment_methods_session_delete_payment_method
// File: crates/router/src/core/payment_methods.rs
// Module: router

pub fn payment_methods_session_delete_payment_method(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    pm_id: id_type::GlobalPaymentMethodId,
    payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
) -> RouterResponse<api::PaymentMethodDeleteResponse>


// File: crates/router/src/core/payments/operations/payment_reject.rs
// Module: router
// Public structs: 1

use std::marker::PhantomData;

use api_models::{enums::FrmSuggestion, payments::PaymentsCancelRequest};
use async_trait::async_trait;
use error_stack::ResultExt;
use router_derive;
use router_env::{instrument, tracing};

use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
use crate::{
    core::{
        errors::{self, RouterResult, StorageErrorExt},
        payments::{helpers, operations, PaymentAddress, PaymentData},
    },
    events::audit_events::{AuditEvent, AuditEventType},
    routes::{app::ReqState, SessionState},
    services,
    types::{
        api::{self, PaymentIdTypeExt},
        domain,
        storage::{self, enums},
    },
    utils::OptionExt,
};

#[derive(Debug, Clone, Copy, router_derive::PaymentOperation)]
#[operation(operations = "all", flow = "cancel")]
pub struct PaymentReject;

type PaymentRejectOperation<'b, F> = BoxedOperation<'b, F, PaymentsCancelRequest, PaymentData<F>>;

#[async_trait]
impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, PaymentsCancelRequest>
    for PaymentReject
{
    #[instrument(skip_all)]
    async fn get_trackers<'a>(
        &'a self,
        state: &'a SessionState,
        payment_id: &api::PaymentIdType,
        _request: &PaymentsCancelRequest,
        merchant_context: &domain::MerchantContext,
        _auth_flow: services::AuthFlow,
        _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<operations::GetTrackerResponse<'a, F, PaymentsCancelRequest, PaymentData<F>>>
    {
        let db = &*state.store;
        let key_manager_state = &state.into();

        let merchant_id = merchant_context.get_merchant_account().get_id();
        let storage_scheme = merchant_context.get_merchant_account().storage_scheme;
        let payment_id = payment_id
            .get_payment_intent_id()
            .change_context(errors::ApiErrorResponse::PaymentNotFound)?;

        let payment_intent = db
            .find_payment_intent_by_payment_id_merchant_id(
                key_manager_state,
                &payment_id,
                merchant_id,
                merchant_context.get_merchant_key_store(),
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        helpers::validate_payment_status_against_not_allowed_statuses(
            payment_intent.status,
            &[
                enums::IntentStatus::Cancelled,
                enums::IntentStatus::Failed,
                enums::IntentStatus::Succeeded,
                enums::IntentStatus::Processing,
            ],
            "reject",
        )?;

        let attempt_id = payment_intent.active_attempt.get_id().clone();
        let payment_attempt = db
            .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
                &payment_intent.payment_id,
                merchant_id,
                attempt_id.clone().as_str(),
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        let shipping_address = helpers::get_address_by_id(
            state,
            payment_intent.shipping_address_id.clone(),
            merchant_context.get_merchant_key_store(),
            &payment_intent.payment_id,
            merchant_id,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await?;

        let billing_address = helpers::get_address_by_id(
            state,
            payment_intent.billing_address_id.clone(),
            merchant_context.get_merchant_key_store(),
            &payment_intent.payment_id,
            merchant_id,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await?;

        let payment_method_billing = helpers::get_address_by_id(
            state,
            payment_attempt.payment_method_billing_address_id.clone(),
            merchant_context.get_merchant_key_store(),
            &payment_intent.payment_id,
            merchant_id,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await?;

        let currency = payment_attempt.currency.get_required_value("currency")?;
        let amount = payment_attempt.get_total_amount().into();

        let frm_response = if cfg!(feature = "frm") {
            db.find_fraud_check_by_payment_id(payment_intent.payment_id.clone(), merchant_context.get_merchant_account().get_id().clone())
                .await
                .change_context(errors::ApiErrorResponse::PaymentNotFound)
                .attach_printable_lazy(|| {
                    format!("Error while retrieving frm_response, merchant_id: {:?}, payment_id: {attempt_id}", merchant_context.get_merchant_account().get_id())
                })
                .ok()
        } else {
            None
        };

        let profile_id = payment_intent
            .profile_id
            .as_ref()
            .get_required_value("profile_id")
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("'profile_id' not set in payment intent")?;

        let business_profile = state
            .store
            .find_business_profile_by_profile_id(
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                profile_id,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound {
                id: profile_id.get_string_repr().to_owned(),
            })?;

        let payment_data = PaymentData {
            flow: PhantomData,
            payment_intent,
            payment_attempt,
            currency,
            amount,
            email: None,
            mandate_id: None,
            mandate_connector: None,
            setup_mandate: None,
            customer_acceptance: None,
            token: None,
            address: PaymentAddress::new(
                shipping_address.as_ref().map(From::from),
                billing_address.as_ref().map(From::from),
                payment_method_billing.as_ref().map(From::from),
                business_profile.use_billing_as_payment_method_billing,
            ),
            token_data: None,
            confirm: None,
            payment_method_data: None,
            payment_method_token: None,
            payment_method_info: None,
            force_sync: None,
            all_keys_required: None,
            refunds: vec![],
            disputes: vec![],
            attempts: None,
            sessions_token: vec![],
            card_cvc: None,
            creds_identifier: None,
            pm_token: None,
            connector_customer_id: None,
            recurring_mandate_payment_data: None,
            ephemeral_key: None,
            multiple_capture_data: None,
            redirect_response: None,
            surcharge_details: None,
            frm_message: frm_response,
            payment_link_data: None,
            incremental_authorization_details: None,
            authorizations: vec![],
            authentication: None,
            recurring_details: None,
            poll_config: None,
            tax_data: None,
            session_id: None,
            service_details: None,
            card_testing_guard_data: None,
            vault_operation: None,
            threeds_method_comp_ind: None,
            whole_connector_response: None,
            is_manual_retry_enabled: None,
        };

        let get_trackers_response = operations::GetTrackerResponse {
            operation: Box::new(self),
            customer_details: None,
            payment_data,
            business_profile,
            mandate_type: None,
        };

        Ok(get_trackers_response)
    }
}

#[async_trait]
impl<F: Clone + Sync> UpdateTracker<F, PaymentData<F>, PaymentsCancelRequest> for PaymentReject {
    #[instrument(skip_all)]
    async fn update_trackers<'b>(
        &'b self,
        state: &'b SessionState,
        req_state: ReqState,
        mut payment_data: PaymentData<F>,
        _customer: Option<domain::Customer>,
        storage_scheme: enums::MerchantStorageScheme,
        _updated_customer: Option<storage::CustomerUpdate>,
        key_store: &domain::MerchantKeyStore,
        _should_decline_transaction: Option<FrmSuggestion>,
        _header_payload: hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<(PaymentRejectOperation<'b, F>, PaymentData<F>)>
    where
        F: 'b + Send,
    {
        let intent_status_update = storage::PaymentIntentUpdate::RejectUpdate {
            status: enums::IntentStatus::Failed,
            merchant_decision: Some(enums::MerchantDecision::Rejected.to_string()),
            updated_by: storage_scheme.to_string(),
        };
        let (error_code, error_message) =
            payment_data
                .frm_message
                .clone()
                .map_or((None, None), |fraud_check| {
                    (
                        Some(Some(fraud_check.frm_status.to_string())),
                        Some(fraud_check.frm_reason.map(|reason| reason.to_string())),
                    )
                });
        let attempt_status_update = storage::PaymentAttemptUpdate::RejectUpdate {
            status: enums::AttemptStatus::Failure,
            error_code,
            error_message,
            updated_by: storage_scheme.to_string(),
        };

        payment_data.payment_intent = state
            .store
            .update_payment_intent(
                &state.into(),
                payment_data.payment_intent,
                intent_status_update,
                key_store,
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        payment_data.payment_attempt = state
            .store
            .update_payment_attempt_with_attempt_id(
                payment_data.payment_attempt.clone(),
                attempt_status_update,
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
        let error_code = payment_data.payment_attempt.error_code.clone();
        let error_message = payment_data.payment_attempt.error_message.clone();
        req_state
            .event_context
            .event(AuditEvent::new(AuditEventType::PaymentReject {
                error_code,
                error_message,
            }))
            .with(payment_data.to_event())
            .emit();

        Ok((Box::new(self), payment_data))
    }
}

impl<F: Send + Clone + Sync> ValidateRequest<F, PaymentsCancelRequest, PaymentData<F>>
    for PaymentReject
{
    #[instrument(skip_all)]
    fn validate_request<'a, 'b>(
        &'b self,
        request: &PaymentsCancelRequest,
        merchant_context: &'a domain::MerchantContext,
    ) -> RouterResult<(PaymentRejectOperation<'b, F>, operations::ValidateResult)> {
        Ok((
            Box::new(self),
            operations::ValidateResult {
                merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
                payment_id: api::PaymentIdType::PaymentIntentId(request.payment_id.to_owned()),
                storage_scheme: merchant_context.get_merchant_account().storage_scheme,
                requeue: false,
            },
        ))
    }
}


// Struct: BitpayPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/bitpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BitpayPaymentsRequest


// File: crates/hyperswitch_connectors/src/connectors/paystack.rs
// Module: hyperswitch_connectors
// Public functions: 1
// Public structs: 1

pub mod transformers;
use std::sync::LazyLock;

use common_enums::enums;
use common_utils::{
    crypto,
    errors::CustomResult,
    ext_traits::{ByteSliceExt, BytesExt},
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, MinorUnit, MinorUnitForConnector},
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks,
};
use masking::{ExposeInterface, Mask};
use transformers as paystack;

use crate::{constants::headers, types::ResponseRouterData, utils};

#[derive(Clone)]
pub struct Paystack {
    amount_converter: &'static (dyn AmountConvertor<Output = MinorUnit> + Sync),
}

impl Paystack {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &MinorUnitForConnector,
        }
    }
}

impl api::Payment for Paystack {}
impl api::PaymentSession for Paystack {}
impl api::ConnectorAccessToken for Paystack {}
impl api::MandateSetup for Paystack {}
impl api::PaymentAuthorize for Paystack {}
impl api::PaymentSync for Paystack {}
impl api::PaymentCapture for Paystack {}
impl api::PaymentVoid for Paystack {}
impl api::Refund for Paystack {}
impl api::RefundExecute for Paystack {}
impl api::RefundSync for Paystack {}
impl api::PaymentToken for Paystack {}

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Paystack
{
    // Not Implemented (R)
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Paystack
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let mut header = vec![(
            headers::CONTENT_TYPE.to_string(),
            self.get_content_type().to_string().into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }
}

impl ConnectorCommon for Paystack {
    fn id(&self) -> &'static str {
        "paystack"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Minor
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.paystack.base_url.as_ref()
    }

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = paystack::PaystackAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            format!("Bearer {}", auth.api_key.expose()).into_masked(),
        )])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: paystack::PaystackErrorResponse = res
            .response
            .parse_struct("PaystackErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        let error_message = paystack::get_error_message(response.clone());

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.code,
            message: error_message,
            reason: Some(response.message),
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorValidation for Paystack {
    //TODO: implement functions when support enabled
}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Paystack {
    //TODO: implement sessions flow
}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Paystack {}

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
    for Paystack
{
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Paystack {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}/charge", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;

        let connector_router_data = paystack::PaystackRouterData::from((amount, req));
        let connector_req = paystack::PaystackPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(types::PaymentsAuthorizeType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(types::PaymentsAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: paystack::PaystackPaymentsResponse = res
            .response
            .parse_struct("Paystack PaymentsAuthorizeResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Paystack {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let connector_payment_id = req
            .request
            .connector_transaction_id
            .get_connector_transaction_id()
            .change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
        Ok(format!(
            "{}{}{}",
            self.base_url(connectors),
            "/transaction/verify/",
            connector_payment_id,
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: paystack::PaystackPSyncResponse = res
            .response
            .parse_struct("paystack PaymentsSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Paystack {
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn get_request_body(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
    }

    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsCaptureType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(types::PaymentsCaptureType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: paystack::PaystackPaymentsResponse = res
            .response
            .parse_struct("Paystack PaymentsCaptureResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Paystack {}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Paystack {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}/refund", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let refund_amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;

        let connector_router_data = paystack::PaystackRouterData::from((refund_amount, req));
        let connector_req = paystack::PaystackRefundRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::RefundExecuteType::get_headers(
                self, req, connectors,
            )?)
            .set_body(types::RefundExecuteType::get_request_body(
                self, req, connectors,
            )?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        let response: paystack::PaystackRefundsResponse = res
            .response
            .parse_struct("paystack RefundResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Paystack {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let connector_refund_id = req
            .request
            .connector_refund_id
            .clone()
            .ok_or(errors::ConnectorError::MissingConnectorRefundID)?;
        Ok(format!(
            "{}{}{}",
            self.base_url(connectors),
            "/refund/",
            connector_refund_id,
        ))
    }

    fn build_request(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&types::RefundSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::RefundSyncType::get_headers(self, req, connectors)?)
                .set_body(types::RefundSyncType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: paystack::PaystackRefundsResponse = res
            .response
            .parse_struct("paystack RefundSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Paystack {
    fn get_webhook_source_verification_algorithm(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
        Ok(Box::new(crypto::HmacSha512))
    }

    fn get_webhook_source_verification_signature(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let signature = utils::get_header_key_value("x-paystack-signature", request.headers)
            .change_context(errors::ConnectorError::WebhookSignatureNotFound)?;

        hex::decode(signature)
            .change_context(errors::ConnectorError::WebhookVerificationSecretInvalid)
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let message = std::str::from_utf8(request.body)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        Ok(message.to_string().into_bytes())
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let webhook_body = request
            .body
            .parse_struct::<paystack::PaystackWebhookData>("PaystackWebhookData")
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        match webhook_body.data {
            paystack::PaystackWebhookEventData::Payment(data) => {
                Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                    api_models::payments::PaymentIdType::ConnectorTransactionId(data.reference),
                ))
            }
            paystack::PaystackWebhookEventData::Refund(data) => {
                Ok(api_models::webhooks::ObjectReferenceId::RefundId(
                    api_models::webhooks::RefundIdType::ConnectorRefundId(data.id),
                ))
            }
        }
    }

    fn get_webhook_event_type(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        let webhook_body = request
            .body
            .parse_struct::<paystack::PaystackWebhookData>("PaystackWebhookData")
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        Ok(api_models::webhooks::IncomingWebhookEvent::from(
            webhook_body.data,
        ))
    }

    fn get_webhook_resource_object(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let webhook_body = request
            .body
            .parse_struct::<paystack::PaystackWebhookData>("PaystackWebhookData")
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        Ok(match webhook_body.data {
            paystack::PaystackWebhookEventData::Payment(payment_webhook_data) => {
                Box::new(payment_webhook_data)
            }
            paystack::PaystackWebhookEventData::Refund(refund_webhook_data) => {
                Box::new(refund_webhook_data)
            }
        })
    }
}

static PAYSTACK_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
    LazyLock::new(|| {
        let supported_capture_methods = vec![
            enums::CaptureMethod::Automatic,
            enums::CaptureMethod::SequentialAutomatic,
        ];

        let mut paystack_supported_payment_methods = SupportedPaymentMethods::new();

        paystack_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Eft,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods,
                specific_features: None,
            },
        );

        paystack_supported_payment_methods
    });

static PAYSTACK_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Paystack",
    description: "Paystack is a Nigerian financial technology company that provides online and offline payment solutions to businesses across Africa.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Sandbox,
};

static PAYSTACK_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 2] =
    [enums::EventClass::Payments, enums::EventClass::Refunds];

impl ConnectorSpecifications for Paystack {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&PAYSTACK_CONNECTOR_INFO)
    }

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        Some(&*PAYSTACK_SUPPORTED_PAYMENT_METHODS)
    }

    fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
        Some(&PAYSTACK_SUPPORTED_WEBHOOK_FLOWS)
    }
}


// File: crates/external_services/src/managers/secrets_management.rs
// Module: external_services
// Public functions: 2

//! Secrets management util module

use common_utils::errors::CustomResult;
#[cfg(feature = "hashicorp-vault")]
use error_stack::ResultExt;
use hyperswitch_interfaces::secrets_interface::{
    SecretManagementInterface, SecretsManagementError,
};

#[cfg(feature = "aws_kms")]
use crate::aws_kms;
#[cfg(feature = "hashicorp-vault")]
use crate::hashicorp_vault;
use crate::no_encryption::core::NoEncryption;

/// Enum representing configuration options for secrets management.
#[derive(Debug, Clone, Default, serde::Deserialize)]
#[serde(tag = "secrets_manager")]
#[serde(rename_all = "snake_case")]
pub enum SecretsManagementConfig {
    /// AWS KMS configuration
    #[cfg(feature = "aws_kms")]
    AwsKms {
        /// AWS KMS config
        aws_kms: aws_kms::core::AwsKmsConfig,
    },

    /// HashiCorp-Vault configuration
    #[cfg(feature = "hashicorp-vault")]
    HashiCorpVault {
        /// HC-Vault config
        hc_vault: hashicorp_vault::core::HashiCorpVaultConfig,
    },

    /// Variant representing no encryption
    #[default]
    NoEncryption,
}

impl SecretsManagementConfig {
    /// Verifies that the client configuration is usable
    pub fn validate(&self) -> Result<(), &'static str> {
        match self {
            #[cfg(feature = "aws_kms")]
            Self::AwsKms { aws_kms } => aws_kms.validate(),
            #[cfg(feature = "hashicorp-vault")]
            Self::HashiCorpVault { hc_vault } => hc_vault.validate(),
            Self::NoEncryption => Ok(()),
        }
    }

    /// Retrieves the appropriate secret management client based on the configuration.
    pub async fn get_secret_management_client(
        &self,
    ) -> CustomResult<Box<dyn SecretManagementInterface>, SecretsManagementError> {
        match self {
            #[cfg(feature = "aws_kms")]
            Self::AwsKms { aws_kms } => {
                Ok(Box::new(aws_kms::core::AwsKmsClient::new(aws_kms).await))
            }
            #[cfg(feature = "hashicorp-vault")]
            Self::HashiCorpVault { hc_vault } => {
                hashicorp_vault::core::HashiCorpVault::new(hc_vault)
                    .change_context(SecretsManagementError::ClientCreationFailed)
                    .map(|inner| -> Box<dyn SecretManagementInterface> { Box::new(inner) })
            }
            Self::NoEncryption => Ok(Box::new(NoEncryption)),
        }
    }
}


// Struct: RefundBodyResponse
// File: crates/hyperswitch_connectors/src/connectors/bamboraapac/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundBodyResponse


// Struct: KafkaFraudCheckEvent
// File: crates/router/src/services/kafka/fraud_check_event.rs
// Module: router
// Implementations: 2
// Traits: super::KafkaMessage

pub struct KafkaFraudCheckEvent<'a>


// File: crates/router/src/types/api/mandates.rs
// Module: router

use ::payment_methods::controller::PaymentMethodsController;
use api_models::mandates;
pub use api_models::mandates::{MandateId, MandateResponse, MandateRevokedResponse};
use common_utils::ext_traits::OptionExt;
use error_stack::ResultExt;
use serde::{Deserialize, Serialize};

use crate::{
    core::{
        errors::{self, RouterResult, StorageErrorExt},
        payment_methods,
    },
    newtype,
    routes::SessionState,
    types::{
        api, domain,
        storage::{self, enums as storage_enums},
    },
};

newtype!(
    pub MandateCardDetails = mandates::MandateCardDetails,
    derives = (Default, Debug, Deserialize, Serialize)
);

#[async_trait::async_trait]
pub(crate) trait MandateResponseExt: Sized {
    async fn from_db_mandate(
        state: &SessionState,
        key_store: domain::MerchantKeyStore,
        mandate: storage::Mandate,
        merchant_account: &domain::MerchantAccount,
    ) -> RouterResult<Self>;
}

#[cfg(feature = "v1")]
#[async_trait::async_trait]
impl MandateResponseExt for MandateResponse {
    async fn from_db_mandate(
        state: &SessionState,
        key_store: domain::MerchantKeyStore,
        mandate: storage::Mandate,
        merchant_account: &domain::MerchantAccount,
    ) -> RouterResult<Self> {
        let db = &*state.store;
        let payment_method = db
            .find_payment_method(
                &(state.into()),
                &key_store,
                &mandate.payment_method_id,
                merchant_account.storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;

        let pm = payment_method
            .get_payment_method_type()
            .get_required_value("payment_method")
            .change_context(errors::ApiErrorResponse::PaymentMethodNotFound)
            .attach_printable("payment_method not found")?;

        let card = if pm == storage_enums::PaymentMethod::Card {
            // if locker is disabled , decrypt the payment method data
            let card_details = if state.conf.locker.locker_enabled {
                let card = payment_methods::cards::get_card_from_locker(
                    state,
                    &payment_method.customer_id,
                    &payment_method.merchant_id,
                    payment_method
                        .locker_id
                        .as_ref()
                        .unwrap_or(payment_method.get_id()),
                )
                .await?;

                payment_methods::transformers::get_card_detail(&payment_method, card)
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed while getting card details")?
            } else {
                let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                    domain::Context(merchant_account.clone(), key_store),
                ));
                payment_methods::cards::PmCards {
                    state,
                    merchant_context: &merchant_context,
                }
                .get_card_details_without_locker_fallback(&payment_method)
                .await?
            };

            Some(MandateCardDetails::from(card_details).into_inner())
        } else {
            None
        };
        let payment_method_type = payment_method
            .get_payment_method_subtype()
            .map(|pmt| pmt.to_string());
        let user_agent = mandate.get_user_agent_extended().unwrap_or_default();
        Ok(Self {
            mandate_id: mandate.mandate_id,
            customer_acceptance: Some(api::payments::CustomerAcceptance {
                acceptance_type: if mandate.customer_ip_address.is_some() {
                    api::payments::AcceptanceType::Online
                } else {
                    api::payments::AcceptanceType::Offline
                },
                accepted_at: mandate.customer_accepted_at,
                online: Some(api::payments::OnlineMandate {
                    ip_address: mandate.customer_ip_address,
                    user_agent,
                }),
            }),
            card,
            status: mandate.mandate_status,
            payment_method: pm.to_string(),
            payment_method_type,
            payment_method_id: mandate.payment_method_id,
        })
    }
}

#[cfg(feature = "v2")]
#[async_trait::async_trait]
impl MandateResponseExt for MandateResponse {
    async fn from_db_mandate(
        state: &SessionState,
        key_store: domain::MerchantKeyStore,
        mandate: storage::Mandate,
        merchant_account: &domain::MerchantAccount,
    ) -> RouterResult<Self> {
        todo!()
    }
}

#[cfg(feature = "v1")]
impl From<api::payment_methods::CardDetailFromLocker> for MandateCardDetails {
    fn from(card_details_from_locker: api::payment_methods::CardDetailFromLocker) -> Self {
        mandates::MandateCardDetails {
            last4_digits: card_details_from_locker.last4_digits,
            card_exp_month: card_details_from_locker.expiry_month.clone(),
            card_exp_year: card_details_from_locker.expiry_year.clone(),
            card_holder_name: card_details_from_locker.card_holder_name,
            card_token: card_details_from_locker.card_token,
            scheme: card_details_from_locker.scheme,
            issuer_country: card_details_from_locker.issuer_country,
            card_fingerprint: card_details_from_locker.card_fingerprint,
            card_isin: card_details_from_locker.card_isin,
            card_issuer: card_details_from_locker.card_issuer,
            card_network: card_details_from_locker.card_network,
            card_type: card_details_from_locker.card_type,
            nick_name: card_details_from_locker.nick_name,
        }
        .into()
    }
}

#[cfg(feature = "v2")]
impl From<api::payment_methods::CardDetailFromLocker> for MandateCardDetails {
    fn from(card_details_from_locker: api::payment_methods::CardDetailFromLocker) -> Self {
        mandates::MandateCardDetails {
            last4_digits: card_details_from_locker.last4_digits,
            card_exp_month: card_details_from_locker.expiry_month.clone(),
            card_exp_year: card_details_from_locker.expiry_year.clone(),
            card_holder_name: card_details_from_locker.card_holder_name,
            card_token: None,
            scheme: None,
            issuer_country: card_details_from_locker
                .issuer_country
                .map(|country| country.to_string()),
            card_fingerprint: card_details_from_locker.card_fingerprint,
            card_isin: card_details_from_locker.card_isin,
            card_issuer: card_details_from_locker.card_issuer,
            card_network: card_details_from_locker.card_network,
            card_type: card_details_from_locker
                .card_type
                .as_ref()
                .map(|c| c.to_string()),
            nick_name: card_details_from_locker.nick_name,
        }
        .into()
    }
}


// Struct: ApplicationInformation
// File: crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ApplicationInformation


// Function: new_list
// File: crates/hyperswitch_connectors/src/connectors/netcetera/netcetera_types.rs
// Module: hyperswitch_connectors

pub fn new_list(value: Vec<T>) -> Self


// File: crates/hyperswitch_connectors/src/connectors/affirm/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 26

use common_enums::{enums, CountryAlpha2, Currency};
use common_utils::{pii, request::Method, types::MinorUnit};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    payment_method_data::{PayLaterData, PaymentMethodData},
    router_data::{ConnectorAuthType, RouterData},
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::{PaymentsCancelData, PaymentsCaptureData, ResponseId},
    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsCompleteAuthorizeRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{PaymentsAuthorizeRequestData, RouterData as OtherRouterData},
};
pub struct AffirmRouterData<T> {
    pub amount: MinorUnit,
    pub router_data: T,
}

impl<T> From<(MinorUnit, T)> for AffirmRouterData<T> {
    fn from((amount, item): (MinorUnit, T)) -> Self {
        Self {
            amount,
            router_data: item,
        }
    }
}

#[derive(Debug, Serialize)]
pub struct AffirmPaymentsRequest {
    pub merchant: Merchant,
    pub items: Vec<Item>,
    pub shipping: Option<Shipping>,
    pub billing: Option<Billing>,
    pub total: MinorUnit,
    pub currency: Currency,
    pub order_id: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct AffirmCompleteAuthorizeRequest {
    pub order_id: Option<String>,
    pub reference_id: Option<String>,
    pub transaction_id: String,
}

impl TryFrom<&PaymentsCompleteAuthorizeRouterData> for AffirmCompleteAuthorizeRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentsCompleteAuthorizeRouterData) -> Result<Self, Self::Error> {
        let transaction_id = item.request.connector_transaction_id.clone().ok_or(
            errors::ConnectorError::MissingRequiredField {
                field_name: "connector_transaction_id",
            },
        )?;

        let reference_id = item.reference_id.clone();
        let order_id = item.connector_request_reference_id.clone();
        Ok(Self {
            transaction_id,
            order_id: Some(order_id),
            reference_id,
        })
    }
}

#[derive(Debug, Serialize)]
pub struct Merchant {
    pub public_api_key: Secret<String>,
    pub user_confirmation_url: String,
    pub user_cancel_url: String,
    pub user_confirmation_url_action: Option<String>,
    pub use_vcn: Option<String>,
    pub name: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct Item {
    pub display_name: String,
    pub sku: String,
    pub unit_price: MinorUnit,
    pub qty: i64,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Shipping {
    pub name: Name,
    pub address: Address,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub phone_number: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email: Option<pii::Email>,
}
#[derive(Debug, Serialize)]
pub struct Billing {
    pub name: Name,
    pub address: Address,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub phone_number: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email: Option<pii::Email>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Name {
    pub first: Option<Secret<String>>,
    pub last: Option<Secret<String>>,
    pub full: Option<Secret<String>>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Address {
    pub line1: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub line2: Option<Secret<String>>,
    pub city: Option<String>,
    pub state: Option<Secret<String>>,
    pub zipcode: Option<Secret<String>>,
    pub country: Option<CountryAlpha2>,
}

#[derive(Debug, Serialize)]
pub struct Metadata {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub shipping_type: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub entity_name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub platform_type: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub platform_version: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub platform_affirm: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub webhook_session_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub mode: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub customer: Option<Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub itinerary: Option<Vec<Value>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub checkout_channel_type: Option<String>,
    #[serde(rename = "BOPIS", skip_serializing_if = "Option::is_none")]
    pub bopis: Option<bool>,
}

#[derive(Debug, Serialize)]
pub struct Discount {
    pub discount_amount: MinorUnit,
    pub discount_display_name: String,
    pub discount_code: Option<String>,
}

impl TryFrom<&AffirmRouterData<&PaymentsAuthorizeRouterData>> for AffirmPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: &AffirmRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let router_data = &item.router_data;
        let request = &router_data.request;

        let billing = Some(Billing {
            name: Name {
                first: item.router_data.get_optional_billing_first_name(),
                last: item.router_data.get_optional_billing_last_name(),
                full: item.router_data.get_optional_billing_full_name(),
            },
            address: Address {
                line1: item.router_data.get_optional_billing_line1(),
                line2: item.router_data.get_optional_billing_line2(),
                city: item.router_data.get_optional_billing_city(),
                state: item.router_data.get_optional_billing_state(),
                zipcode: item.router_data.get_optional_billing_zip(),
                country: item.router_data.get_optional_billing_country(),
            },
            phone_number: item.router_data.get_optional_billing_phone_number(),
            email: item.router_data.get_optional_billing_email(),
        });

        let shipping = Some(Shipping {
            name: Name {
                first: item.router_data.get_optional_shipping_first_name(),
                last: item.router_data.get_optional_shipping_last_name(),
                full: item.router_data.get_optional_shipping_full_name(),
            },
            address: Address {
                line1: item.router_data.get_optional_shipping_line1(),
                line2: item.router_data.get_optional_shipping_line2(),
                city: item.router_data.get_optional_shipping_city(),
                state: item.router_data.get_optional_shipping_state(),
                zipcode: item.router_data.get_optional_shipping_zip(),
                country: item.router_data.get_optional_shipping_country(),
            },
            phone_number: item.router_data.get_optional_shipping_phone_number(),
            email: item.router_data.get_optional_shipping_email(),
        });

        match request.payment_method_data.clone() {
            PaymentMethodData::PayLater(PayLaterData::AffirmRedirect {}) => {
                let items = match request.order_details.clone() {
                    Some(order_details) => order_details
                        .iter()
                        .map(|data| {
                            Ok(Item {
                                display_name: data.product_name.clone(),
                                sku: data.product_id.clone().unwrap_or_default(),
                                unit_price: data.amount,
                                qty: data.quantity.into(),
                            })
                        })
                        .collect::<Result<Vec<_>, _>>(),
                    None => Err(report!(errors::ConnectorError::MissingRequiredField {
                        field_name: "order_details",
                    })),
                }?;

                let auth_type = AffirmAuthType::try_from(&item.router_data.connector_auth_type)
                    .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
                let public_api_key = auth_type.public_key;
                let merchant = Merchant {
                    public_api_key,
                    user_confirmation_url: request.get_complete_authorize_url()?,
                    user_cancel_url: request.get_router_return_url()?,
                    user_confirmation_url_action: None,
                    use_vcn: None,
                    name: None,
                };

                Ok(Self {
                    merchant,
                    items,
                    shipping,
                    billing,
                    total: item.amount,
                    currency: request.currency,
                    order_id: Some(item.router_data.connector_request_reference_id.clone()),
                })
            }
            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
        }
    }
}
pub struct AffirmAuthType {
    pub public_key: Secret<String>,
    pub private_key: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for AffirmAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
                public_key: api_key.to_owned(),
                private_key: key1.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

impl From<AffirmTransactionStatus> for common_enums::AttemptStatus {
    fn from(item: AffirmTransactionStatus) -> Self {
        match item {
            AffirmTransactionStatus::Authorized => Self::Authorized,
            AffirmTransactionStatus::AuthExpired => Self::Failure,
            AffirmTransactionStatus::Canceled => Self::Voided,
            AffirmTransactionStatus::Captured => Self::Charged,
            AffirmTransactionStatus::ConfirmationExpired => Self::Failure,
            AffirmTransactionStatus::Confirmed => Self::Authorized,
            AffirmTransactionStatus::Created => Self::Pending,
            AffirmTransactionStatus::Declined => Self::Failure,
            AffirmTransactionStatus::Disputed => Self::Unresolved,
            AffirmTransactionStatus::DisputeRefunded => Self::Unresolved,
            AffirmTransactionStatus::ExpiredAuthorization => Self::Failure,
            AffirmTransactionStatus::ExpiredConfirmation => Self::Failure,
            AffirmTransactionStatus::PartiallyCaptured => Self::Charged,
            AffirmTransactionStatus::Voided => Self::Voided,
            AffirmTransactionStatus::PartiallyVoided => Self::Voided,
        }
    }
}

impl From<AffirmRefundStatus> for common_enums::RefundStatus {
    fn from(item: AffirmRefundStatus) -> Self {
        match item {
            AffirmRefundStatus::PartiallyRefunded => Self::Success,
            AffirmRefundStatus::Refunded => Self::Success,
        }
    }
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AffirmPaymentsResponse {
    checkout_id: String,
    redirect_url: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AffirmCompleteAuthorizeResponse {
    pub id: String,
    pub status: AffirmTransactionStatus,
    pub amount: MinorUnit,
    pub amount_refunded: MinorUnit,
    pub authorization_expiration: String,
    pub checkout_id: String,
    pub created: String,
    pub currency: Currency,
    pub events: Vec<TransactionEvent>,
    pub settlement_transaction_id: Option<String>,
    pub transaction_id: String,
    pub order_id: String,
    pub shipping_carrier: Option<String>,
    pub shipping_confirmation: Option<String>,
    pub shipping: Option<Shipping>,
    pub agent_alias: Option<String>,
    pub merchant_transaction_id: Option<String>,
    pub provider_id: Option<i64>,
    pub remove_tax: Option<bool>,
    pub checkout: Option<Value>,
    pub refund_expires: Option<String>,
    pub remaining_capturable_amount: Option<i64>,
    pub loan_information: Option<LoanInformation>,
    pub user_id: Option<String>,
    pub platform: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct TransactionEvent {
    pub id: String,
    pub amount: MinorUnit,
    pub created: String,
    pub currency: Currency,
    pub fee: Option<i64>,
    pub fee_refunded: Option<MinorUnit>,
    pub reference_id: Option<String>,
    #[serde(rename = "type")]
    pub event_type: AffirmEventType,
    pub settlement_transaction_id: Option<String>,
    pub transaction_id: String,
    pub order_id: String,
    pub shipping_carrier: Option<String>,
    pub shipping_confirmation: Option<String>,
    pub shipping: Option<Shipping>,
    pub agent_alias: Option<String>,
    pub merchant_transaction_id: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct LoanInformation {
    pub fees: Option<LoanFees>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct LoanFees {
    pub amount: Option<MinorUnit>,
    pub description: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AffirmTransactionStatus {
    Authorized,
    AuthExpired,
    Canceled,
    Captured,
    ConfirmationExpired,
    Confirmed,
    Created,
    Declined,
    Disputed,
    DisputeRefunded,
    ExpiredAuthorization,
    ExpiredConfirmation,
    PartiallyCaptured,
    Voided,
    PartiallyVoided,
}

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AffirmRefundStatus {
    PartiallyRefunded,
    Refunded,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AffirmPSyncResponse {
    pub amount: MinorUnit,
    pub amount_refunded: MinorUnit,
    pub authorization_expiration: Option<String>,
    pub checkout_id: String,
    pub created: String,
    pub currency: Currency,
    pub events: Vec<TransactionEvent>,
    pub id: String,
    pub order_id: String,
    pub provider_id: Option<i64>,
    pub remove_tax: Option<bool>,
    pub status: AffirmTransactionStatus,
    pub checkout: Option<Value>,
    pub refund_expires: Option<String>,
    pub remaining_capturable_amount: Option<MinorUnit>,
    pub loan_information: Option<LoanInformation>,
    pub shipping_carrier: Option<String>,
    pub shipping_confirmation: Option<String>,
    pub shipping: Option<Shipping>,
    pub merchant_transaction_id: Option<String>,
    pub settlement_transaction_id: Option<String>,
    pub transaction_id: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AffirmRsyncResponse {
    pub amount: MinorUnit,
    pub amount_refunded: MinorUnit,
    pub authorization_expiration: String,
    pub checkout_id: String,
    pub created: String,
    pub currency: Currency,
    pub events: Vec<TransactionEvent>,
    pub id: String,
    pub order_id: String,
    pub status: AffirmRefundStatus,
    pub refund_expires: Option<String>,
    pub remaining_capturable_amount: Option<MinorUnit>,
    pub shipping_carrier: Option<String>,
    pub shipping_confirmation: Option<String>,
    pub shipping: Option<Shipping>,
    pub merchant_transaction_id: Option<String>,
    pub settlement_transaction_id: Option<String>,
    pub transaction_id: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum AffirmResponseWrapper {
    Authorize(AffirmPaymentsResponse),
    Psync(Box<AffirmPSyncResponse>),
}

impl<F, T> TryFrom<ResponseRouterData<F, AffirmResponseWrapper, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: ResponseRouterData<F, AffirmResponseWrapper, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        match &item.response {
            AffirmResponseWrapper::Authorize(resp) => {
                let redirection_data = url::Url::parse(&resp.redirect_url)
                    .ok()
                    .map(|url| RedirectForm::from((url, Method::Get)));

                Ok(Self {
                    status: enums::AttemptStatus::AuthenticationPending,
                    response: Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::ConnectorTransactionId(resp.checkout_id.clone()),
                        redirection_data: Box::new(redirection_data),
                        mandate_reference: Box::new(None),
                        connector_metadata: None,
                        network_txn_id: None,
                        connector_response_reference_id: None,
                        charges: None,
                        incremental_authorization_allowed: None,
                    }),
                    ..item.data
                })
            }
            AffirmResponseWrapper::Psync(resp) => {
                let status = enums::AttemptStatus::from(resp.status);
                Ok(Self {
                    status,
                    response: Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::ConnectorTransactionId(resp.id.clone()),
                        redirection_data: Box::new(None),
                        mandate_reference: Box::new(None),
                        connector_metadata: None,
                        network_txn_id: None,
                        connector_response_reference_id: None,
                        charges: None,
                        incremental_authorization_allowed: None,
                    }),
                    ..item.data
                })
            }
        }
    }
}

impl<F, T> TryFrom<ResponseRouterData<F, AffirmCompleteAuthorizeResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, AffirmCompleteAuthorizeResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: common_enums::AttemptStatus::from(item.response.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}
#[derive(Default, Debug, Serialize)]
pub struct AffirmRefundRequest {
    pub amount: MinorUnit,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reference_id: Option<String>,
}

impl<F> TryFrom<&AffirmRouterData<&RefundsRouterData<F>>> for AffirmRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(item: &AffirmRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        let reference_id = item.router_data.request.connector_transaction_id.clone();

        Ok(Self {
            amount: item.amount.to_owned(),
            reference_id: Some(reference_id),
        })
    }
}

#[allow(dead_code)]
#[derive(Debug, Copy, Serialize, Default, Deserialize, Clone)]
pub enum RefundStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AffirmRefundResponse {
    pub id: String,
    pub amount: MinorUnit,
    pub created: String,
    pub currency: Currency,
    pub fee: Option<MinorUnit>,
    pub fee_refunded: Option<MinorUnit>,
    pub reference_id: Option<String>,
    #[serde(rename = "type")]
    pub event_type: AffirmEventType,
    pub settlement_transaction_id: Option<String>,
    pub transaction_id: String,
    pub order_id: String,
    pub shipping_carrier: Option<String>,
    pub shipping_confirmation: Option<String>,
    pub shipping: Option<Shipping>,
    pub agent_alias: Option<String>,
    pub merchant_transaction_id: Option<String>,
}

impl From<AffirmEventType> for enums::RefundStatus {
    fn from(event_type: AffirmEventType) -> Self {
        match event_type {
            AffirmEventType::Refund => Self::Success,
            _ => Self::Pending,
        }
    }
}

impl TryFrom<RefundsResponseRouterData<Execute, AffirmRefundResponse>>
    for RefundsRouterData<Execute>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, AffirmRefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: enums::RefundStatus::from(item.response.event_type),
            }),
            ..item.data
        })
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, AffirmRsyncResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, AffirmRsyncResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: enums::RefundStatus::from(item.response.status),
            }),
            ..item.data
        })
    }
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
pub struct AffirmErrorResponse {
    pub status_code: u16,
    pub code: String,
    pub message: String,
    #[serde(rename = "type")]
    pub error_type: String,
}

#[derive(Debug, Serialize)]
pub struct AffirmCaptureRequest {
    pub order_id: Option<String>,
    pub reference_id: Option<String>,
    pub amount: MinorUnit,
    pub shipping_carrier: Option<String>,
    pub shipping_confirmation: Option<String>,
}

impl TryFrom<&AffirmRouterData<&PaymentsCaptureRouterData>> for AffirmCaptureRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(item: &AffirmRouterData<&PaymentsCaptureRouterData>) -> Result<Self, Self::Error> {
        let reference_id = match item.router_data.connector_request_reference_id.clone() {
            ref_id if ref_id.is_empty() => None,
            ref_id => Some(ref_id),
        };

        let amount = item.amount;

        Ok(Self {
            reference_id,
            amount,
            order_id: None,
            shipping_carrier: None,
            shipping_confirmation: None,
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AffirmCaptureResponse {
    pub id: String,
    pub amount: MinorUnit,
    pub created: String,
    pub currency: Currency,
    pub fee: Option<MinorUnit>,
    pub fee_refunded: Option<MinorUnit>,
    pub reference_id: Option<String>,
    #[serde(rename = "type")]
    pub event_type: AffirmEventType,
    pub settlement_transaction_id: Option<String>,
    pub transaction_id: String,
    pub order_id: String,
    pub shipping_carrier: Option<String>,
    pub shipping_confirmation: Option<String>,
    pub shipping: Option<Shipping>,
    pub agent_alias: Option<String>,
    pub merchant_transaction_id: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum AffirmEventType {
    Auth,
    AuthExpired,
    Capture,
    ChargeOff,
    Confirm,
    ConfirmationExpired,
    ExpireAuthorization,
    ExpireConfirmation,
    Refund,
    SplitCapture,
    Update,
    Void,
    PartialVoid,
    RefundVoided,
}

impl From<AffirmEventType> for enums::AttemptStatus {
    fn from(event_type: AffirmEventType) -> Self {
        match event_type {
            AffirmEventType::Auth => Self::Authorized,
            AffirmEventType::Capture | AffirmEventType::SplitCapture | AffirmEventType::Confirm => {
                Self::Charged
            }
            AffirmEventType::AuthExpired
            | AffirmEventType::ChargeOff
            | AffirmEventType::ConfirmationExpired
            | AffirmEventType::ExpireAuthorization
            | AffirmEventType::ExpireConfirmation => Self::Failure,
            AffirmEventType::Refund | AffirmEventType::RefundVoided => Self::AutoRefunded,
            AffirmEventType::Update => Self::Pending,
            AffirmEventType::Void | AffirmEventType::PartialVoid => Self::Voided,
        }
    }
}

impl<F>
    TryFrom<ResponseRouterData<F, AffirmCaptureResponse, PaymentsCaptureData, PaymentsResponseData>>
    for RouterData<F, PaymentsCaptureData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            AffirmCaptureResponse,
            PaymentsCaptureData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: enums::AttemptStatus::from(item.response.event_type.clone()),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

impl TryFrom<&PaymentsCancelRouterData> for AffirmCancelRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentsCancelRouterData) -> Result<Self, Self::Error> {
        let request = &item.request;

        let reference_id = request.connector_transaction_id.clone();
        let amount = item
            .request
            .amount
            .ok_or(errors::ConnectorError::MissingRequiredField {
                field_name: "amount",
            })?;
        Ok(Self {
            reference_id: Some(reference_id),
            amount,
            merchant_transaction_id: None,
        })
    }
}

#[derive(Debug, Serialize)]
pub struct AffirmCancelRequest {
    pub reference_id: Option<String>,
    pub amount: i64,
    pub merchant_transaction_id: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AffirmCancelResponse {
    pub id: String,
    pub amount: MinorUnit,
    pub created: String,
    pub currency: Currency,
    pub fee: Option<MinorUnit>,
    pub fee_refunded: Option<MinorUnit>,
    pub reference_id: Option<String>,
    #[serde(rename = "type")]
    pub event_type: AffirmEventType,
    pub settlement_transaction_id: Option<String>,
    pub transaction_id: String,
    pub order_id: String,
    pub shipping_carrier: Option<String>,
    pub shipping_confirmation: Option<String>,
    pub shipping: Option<Shipping>,
    pub agent_alias: Option<String>,
    pub merchant_transaction_id: Option<String>,
}

impl<F>
    TryFrom<ResponseRouterData<F, AffirmCancelResponse, PaymentsCancelData, PaymentsResponseData>>
    for RouterData<F, PaymentsCancelData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, AffirmCancelResponse, PaymentsCancelData, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: enums::AttemptStatus::from(item.response.event_type.clone()),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}


// Struct: ClientAuthCheckInfoResponse
// File: crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ClientAuthCheckInfoResponse


// Struct: RoutingDictionaryRecord
// File: crates/api_models/src/routing.rs
// Module: api_models
// Implementations: 0

pub struct RoutingDictionaryRecord


// Struct: HipayMaintenanceRequest
// File: crates/hyperswitch_connectors/src/connectors/hipay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct HipayMaintenanceRequest


// Struct: GlobalpayCaptureRequest
// File: crates/hyperswitch_connectors/src/connectors/globalpay/requests.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct GlobalpayCaptureRequest


// Implementation: impl MandateSetup for for Threedsecureio
// File: crates/hyperswitch_connectors/src/connectors/threedsecureio.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl MandateSetup for for Threedsecureio


// Function: get_card_details_from_locker
// File: crates/router/src/core/payment_methods/cards.rs
// Module: router

pub fn get_card_details_from_locker(
    state: &routes::SessionState,
    pm: &domain::PaymentMethod,
) -> errors::RouterResult<api::CardDetailFromLocker>


// Function: retrieve_file_and_provider_file_id_from_file_id
// File: crates/router/src/core/files/helpers.rs
// Module: router

pub fn retrieve_file_and_provider_file_id_from_file_id(
    state: &SessionState,
    file_id: Option<String>,
    dispute_id: Option<String>,
    merchant_context: &domain::MerchantContext,
    is_connector_file_data_required: api::FileDataRequired,
) -> CustomResult<FileInfo, errors::ApiErrorResponse>


// Function: set_debit_routing_savings
// File: crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
// Module: hyperswitch_domain_models

pub fn set_debit_routing_savings(&mut self, debit_routing_savings: Option<&MinorUnit>)


// Struct: NmiValidateRequest
// File: crates/hyperswitch_connectors/src/connectors/nmi/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NmiValidateRequest


// Struct: SignedKey
// File: crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SignedKey


// Struct: ResponseIndicators
// File: crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ResponseIndicators