// File: crates/hyperswitch_domain_models/src/payouts/payouts.rs

use common_enums as storage_enums;
use common_utils::{id_type, pii, types::MinorUnit};
use serde::{Deserialize, Serialize};
use storage_enums::MerchantStorageScheme;
use time::PrimitiveDateTime;

use super::payout_attempt::PayoutAttempt;
#[cfg(feature = "olap")]
use super::PayoutFetchConstraints;

#[async_trait::async_trait]
pub trait PayoutsInterface {
    type Error;
    async fn insert_payout(
        &self,
        _payout: PayoutsNew,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<Payouts, Self::Error>;

    async fn find_payout_by_merchant_id_payout_id(
        &self,
        _merchant_id: &id_type::MerchantId,
        _payout_id: &id_type::PayoutId,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<Payouts, Self::Error>;

    async fn update_payout(
        &self,
        _this: &Payouts,
        _payout: PayoutsUpdate,
        _payout_attempt: &PayoutAttempt,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<Payouts, Self::Error>;

    async fn find_optional_payout_by_merchant_id_payout_id(
        &self,
        _merchant_id: &id_type::MerchantId,
        _payout_id: &id_type::PayoutId,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<Option<Payouts>, Self::Error>;

    #[cfg(feature = "olap")]
    async fn filter_payouts_by_constraints(
        &self,
        _merchant_id: &id_type::MerchantId,
        _filters: &PayoutFetchConstraints,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<Vec<Payouts>, Self::Error>;

    #[cfg(feature = "olap")]
    async fn filter_payouts_and_attempts(
        &self,
        _merchant_id: &id_type::MerchantId,
        _filters: &PayoutFetchConstraints,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<
        Vec<(
            Payouts,
            PayoutAttempt,
            Option<diesel_models::Customer>,
            Option<diesel_models::Address>,
        )>,
        Self::Error,
    >;

    #[cfg(feature = "olap")]
    async fn filter_payouts_by_time_range_constraints(
        &self,
        _merchant_id: &id_type::MerchantId,
        _time_range: &common_utils::types::TimeRange,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<Vec<Payouts>, Self::Error>;

    #[cfg(feature = "olap")]
    #[allow(clippy::too_many_arguments)]
    async fn get_total_count_of_filtered_payouts(
        &self,
        _merchant_id: &id_type::MerchantId,
        _active_payout_ids: &[id_type::PayoutId],
        _connector: Option<Vec<api_models::enums::PayoutConnectors>>,
        _currency: Option<Vec<storage_enums::Currency>>,
        _status: Option<Vec<storage_enums::PayoutStatus>>,
        _payout_method: Option<Vec<storage_enums::PayoutType>>,
    ) -> error_stack::Result<i64, Self::Error>;

    #[cfg(feature = "olap")]
    async fn filter_active_payout_ids_by_constraints(
        &self,
        _merchant_id: &id_type::MerchantId,
        _constraints: &PayoutFetchConstraints,
    ) -> error_stack::Result<Vec<id_type::PayoutId>, Self::Error>;
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Payouts {
    pub payout_id: id_type::PayoutId,
    pub merchant_id: id_type::MerchantId,
    pub customer_id: Option<id_type::CustomerId>,
    pub address_id: Option<String>,
    pub payout_type: Option<storage_enums::PayoutType>,
    pub payout_method_id: Option<String>,
    pub amount: MinorUnit,
    pub destination_currency: storage_enums::Currency,
    pub source_currency: storage_enums::Currency,
    pub description: Option<String>,
    pub recurring: bool,
    pub auto_fulfill: bool,
    pub return_url: Option<String>,
    pub entity_type: storage_enums::PayoutEntityType,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: PrimitiveDateTime,
    pub last_modified_at: PrimitiveDateTime,
    pub attempt_count: i16,
    pub profile_id: id_type::ProfileId,
    pub status: storage_enums::PayoutStatus,
    pub confirm: Option<bool>,
    pub payout_link_id: Option<String>,
    pub client_secret: Option<String>,
    pub priority: Option<storage_enums::PayoutSendPriority>,
    pub organization_id: Option<id_type::OrganizationId>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PayoutsNew {
    pub payout_id: id_type::PayoutId,
    pub merchant_id: id_type::MerchantId,
    pub customer_id: Option<id_type::CustomerId>,
    pub address_id: Option<String>,
    pub payout_type: Option<storage_enums::PayoutType>,
    pub payout_method_id: Option<String>,
    pub amount: MinorUnit,
    pub destination_currency: storage_enums::Currency,
    pub source_currency: storage_enums::Currency,
    pub description: Option<String>,
    pub recurring: bool,
    pub auto_fulfill: bool,
    pub return_url: Option<String>,
    pub entity_type: storage_enums::PayoutEntityType,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: PrimitiveDateTime,
    pub last_modified_at: PrimitiveDateTime,
    pub attempt_count: i16,
    pub profile_id: id_type::ProfileId,
    pub status: storage_enums::PayoutStatus,
    pub confirm: Option<bool>,
    pub payout_link_id: Option<String>,
    pub client_secret: Option<String>,
    pub priority: Option<storage_enums::PayoutSendPriority>,
    pub organization_id: Option<id_type::OrganizationId>,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum PayoutsUpdate {
    Update {
        amount: MinorUnit,
        destination_currency: storage_enums::Currency,
        source_currency: storage_enums::Currency,
        description: Option<String>,
        recurring: bool,
        auto_fulfill: bool,
        return_url: Option<String>,
        entity_type: storage_enums::PayoutEntityType,
        metadata: Option<pii::SecretSerdeValue>,
        profile_id: Option<id_type::ProfileId>,
        status: Option<storage_enums::PayoutStatus>,
        confirm: Option<bool>,
        payout_type: Option<storage_enums::PayoutType>,
        address_id: Option<String>,
        customer_id: Option<id_type::CustomerId>,
    },
    PayoutMethodIdUpdate {
        payout_method_id: String,
    },
    RecurringUpdate {
        recurring: bool,
    },
    AttemptCountUpdate {
        attempt_count: i16,
    },
    StatusUpdate {
        status: storage_enums::PayoutStatus,
    },
}

#[derive(Clone, Debug, Default)]
pub struct PayoutsUpdateInternal {
    pub amount: Option<MinorUnit>,
    pub destination_currency: Option<storage_enums::Currency>,
    pub source_currency: Option<storage_enums::Currency>,
    pub description: Option<String>,
    pub recurring: Option<bool>,
    pub auto_fulfill: Option<bool>,
    pub return_url: Option<String>,
    pub entity_type: Option<storage_enums::PayoutEntityType>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub payout_method_id: Option<String>,
    pub profile_id: Option<id_type::ProfileId>,
    pub status: Option<storage_enums::PayoutStatus>,
    pub attempt_count: Option<i16>,
    pub confirm: Option<bool>,
    pub payout_type: Option<common_enums::PayoutType>,
    pub address_id: Option<String>,
    pub customer_id: Option<id_type::CustomerId>,
}

impl From<PayoutsUpdate> for PayoutsUpdateInternal {
    fn from(payout_update: PayoutsUpdate) -> Self {
        match payout_update {
            PayoutsUpdate::Update {
                amount,
                destination_currency,
                source_currency,
                description,
                recurring,
                auto_fulfill,
                return_url,
                entity_type,
                metadata,
                profile_id,
                status,
                confirm,
                payout_type,
                address_id,
                customer_id,
            } => Self {
                amount: Some(amount),
                destination_currency: Some(destination_currency),
                source_currency: Some(source_currency),
                description,
                recurring: Some(recurring),
                auto_fulfill: Some(auto_fulfill),
                return_url,
                entity_type: Some(entity_type),
                metadata,
                profile_id,
                status,
                confirm,
                payout_type,
                address_id,
                customer_id,
                ..Default::default()
            },
            PayoutsUpdate::PayoutMethodIdUpdate { payout_method_id } => Self {
                payout_method_id: Some(payout_method_id),
                ..Default::default()
            },
            PayoutsUpdate::RecurringUpdate { recurring } => Self {
                recurring: Some(recurring),
                ..Default::default()
            },
            PayoutsUpdate::AttemptCountUpdate { attempt_count } => Self {
                attempt_count: Some(attempt_count),
                ..Default::default()
            },
            PayoutsUpdate::StatusUpdate { status } => Self {
                status: Some(status),
                ..Default::default()
            },
        }
    }
}


// File: crates/hyperswitch_domain_models/src/payouts/payout_attempt.rs

use api_models::enums::PayoutConnectors;
use common_enums as storage_enums;
use common_utils::{
    id_type, payout_method_utils, pii,
    types::{UnifiedCode, UnifiedMessage},
};
use serde::{Deserialize, Serialize};
use storage_enums::MerchantStorageScheme;
use time::PrimitiveDateTime;

use super::payouts::Payouts;

#[async_trait::async_trait]
pub trait PayoutAttemptInterface {
    type Error;
    async fn insert_payout_attempt(
        &self,
        _payout_attempt: PayoutAttemptNew,
        _payouts: &Payouts,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<PayoutAttempt, Self::Error>;

    async fn update_payout_attempt(
        &self,
        _this: &PayoutAttempt,
        _payout_attempt_update: PayoutAttemptUpdate,
        _payouts: &Payouts,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<PayoutAttempt, Self::Error>;

    async fn find_payout_attempt_by_merchant_id_payout_attempt_id(
        &self,
        _merchant_id: &id_type::MerchantId,
        _payout_attempt_id: &str,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<PayoutAttempt, Self::Error>;

    async fn find_payout_attempt_by_merchant_id_connector_payout_id(
        &self,
        _merchant_id: &id_type::MerchantId,
        _connector_payout_id: &str,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<PayoutAttempt, Self::Error>;

    async fn find_payout_attempt_by_merchant_id_merchant_order_reference_id(
        &self,
        _merchant_id: &id_type::MerchantId,
        _merchant_order_reference_id: &str,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<PayoutAttempt, Self::Error>;

    async fn get_filters_for_payouts(
        &self,
        _payout: &[Payouts],
        _merchant_id: &id_type::MerchantId,
        _storage_scheme: MerchantStorageScheme,
    ) -> error_stack::Result<PayoutListFilters, Self::Error>;
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PayoutListFilters {
    pub connector: Vec<PayoutConnectors>,
    pub currency: Vec<storage_enums::Currency>,
    pub status: Vec<storage_enums::PayoutStatus>,
    pub payout_method: Vec<storage_enums::PayoutType>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct PayoutAttempt {
    pub payout_attempt_id: String,
    pub payout_id: id_type::PayoutId,
    pub customer_id: Option<id_type::CustomerId>,
    pub merchant_id: id_type::MerchantId,
    pub address_id: Option<String>,
    pub connector: Option<String>,
    pub connector_payout_id: Option<String>,
    pub payout_token: Option<String>,
    pub status: storage_enums::PayoutStatus,
    pub is_eligible: Option<bool>,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub last_modified_at: PrimitiveDateTime,
    pub profile_id: id_type::ProfileId,
    pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
    pub routing_info: Option<serde_json::Value>,
    pub unified_code: Option<UnifiedCode>,
    pub unified_message: Option<UnifiedMessage>,
    pub additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    pub merchant_order_reference_id: Option<String>,
    pub payout_connector_metadata: Option<pii::SecretSerdeValue>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct PayoutAttemptNew {
    pub payout_attempt_id: String,
    pub payout_id: id_type::PayoutId,
    pub customer_id: Option<id_type::CustomerId>,
    pub merchant_id: id_type::MerchantId,
    pub address_id: Option<String>,
    pub connector: Option<String>,
    pub connector_payout_id: Option<String>,
    pub payout_token: Option<String>,
    pub status: storage_enums::PayoutStatus,
    pub is_eligible: Option<bool>,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<String>,
    pub created_at: PrimitiveDateTime,
    pub last_modified_at: PrimitiveDateTime,
    pub profile_id: id_type::ProfileId,
    pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
    pub routing_info: Option<serde_json::Value>,
    pub unified_code: Option<UnifiedCode>,
    pub unified_message: Option<UnifiedMessage>,
    pub additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    pub merchant_order_reference_id: Option<String>,
    pub payout_connector_metadata: Option<pii::SecretSerdeValue>,
}

#[derive(Debug, Clone)]
pub enum PayoutAttemptUpdate {
    StatusUpdate {
        connector_payout_id: Option<String>,
        status: storage_enums::PayoutStatus,
        error_message: Option<String>,
        error_code: Option<String>,
        is_eligible: Option<bool>,

        unified_code: Option<UnifiedCode>,
        unified_message: Option<UnifiedMessage>,
        payout_connector_metadata: Option<pii::SecretSerdeValue>,
    },
    PayoutTokenUpdate {
        payout_token: String,
    },
    BusinessUpdate {
        business_country: Option<storage_enums::CountryAlpha2>,
        business_label: Option<String>,
        address_id: Option<String>,
        customer_id: Option<id_type::CustomerId>,
    },
    UpdateRouting {
        connector: String,
        routing_info: Option<serde_json::Value>,
        merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
    },
    AdditionalPayoutMethodDataUpdate {
        additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    },
}

#[derive(Clone, Debug, Default)]
pub struct PayoutAttemptUpdateInternal {
    pub payout_token: Option<String>,
    pub connector_payout_id: Option<String>,
    pub status: Option<storage_enums::PayoutStatus>,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub is_eligible: Option<bool>,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<String>,
    pub connector: Option<String>,
    pub routing_info: Option<serde_json::Value>,
    pub address_id: Option<String>,
    pub customer_id: Option<id_type::CustomerId>,
    pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
    pub unified_code: Option<UnifiedCode>,
    pub unified_message: Option<UnifiedMessage>,
    pub additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    pub payout_connector_metadata: Option<pii::SecretSerdeValue>,
}

impl From<PayoutAttemptUpdate> for PayoutAttemptUpdateInternal {
    fn from(payout_update: PayoutAttemptUpdate) -> Self {
        match payout_update {
            PayoutAttemptUpdate::PayoutTokenUpdate { payout_token } => Self {
                payout_token: Some(payout_token),
                ..Default::default()
            },
            PayoutAttemptUpdate::StatusUpdate {
                connector_payout_id,
                status,
                error_message,
                error_code,
                is_eligible,
                unified_code,
                unified_message,
                payout_connector_metadata,
            } => Self {
                connector_payout_id,
                status: Some(status),
                error_message,
                error_code,
                is_eligible,
                unified_code,
                unified_message,
                payout_connector_metadata,
                ..Default::default()
            },
            PayoutAttemptUpdate::BusinessUpdate {
                business_country,
                business_label,
                address_id,
                customer_id,
            } => Self {
                business_country,
                business_label,
                address_id,
                customer_id,
                ..Default::default()
            },
            PayoutAttemptUpdate::UpdateRouting {
                connector,
                routing_info,
                merchant_connector_id,
            } => Self {
                connector: Some(connector),
                routing_info,
                merchant_connector_id,
                ..Default::default()
            },
            PayoutAttemptUpdate::AdditionalPayoutMethodDataUpdate {
                additional_payout_method_data,
            } => Self {
                additional_payout_method_data,
                ..Default::default()
            },
        }
    }
}


// File: crates/hyperswitch_connectors/Cargo.toml

[package]
name = "hyperswitch_connectors"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true

[features]
frm = ["hyperswitch_domain_models/frm", "hyperswitch_interfaces/frm"]
payouts = ["hyperswitch_domain_models/payouts", "api_models/payouts", "hyperswitch_interfaces/payouts"]
v1 = ["api_models/v1", "hyperswitch_domain_models/v1", "common_utils/v1"]
v2 = ["api_models/v2", "hyperswitch_domain_models/v2", "common_utils/v2", "hyperswitch_interfaces/v2"]
revenue_recovery = ["hyperswitch_interfaces/revenue_recovery", "hyperswitch_domain_models/revenue_recovery"]
default = ["dummy_connector"]
dummy_connector = [
    "hyperswitch_interfaces/dummy_connector",
    "hyperswitch_domain_models/dummy_connector",
]

[dependencies]
actix-web = "4.11.0"
async-trait = "0.1.88"
base64 = "0.22.1"
bytes = "1.10.1"
chrono = "0.4"
crc = "3"
crypto = "0.2"
encoding_rs = "0.8.35"
error-stack = "0.4.1"
hex = "0.4.3"
html-escape = "0.2"
http = "0.2.12"
iso_currency = "0.4.4"
isocountry = "0.3.2"
image = { version = "0.25.6", default-features = false, features = ["png"] }
josekit = "0.8.7"
lazy_static = "1.5.0"
mime = "0.3.17"
num-traits = "0.2.19"
nanoid = "0.4.0"
openssl = {version = "0.10.70"}
pem = "3.0.5"
qrcode = "0.14.1"
quick-xml = { version = "0.31.0", features = ["serialize"] }
rand = "0.8.5"
regex = "1.11.1"
reqwest = { version = "0.11.27" }
ring = "0.17.14"
roxmltree = "0.19.0"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
serde_qs = "0.12.0"
serde_repr = "0.1.20"
serde_urlencoded = "0.7.1"
unidecode = "0.3.0"
serde_with = "3.12.0"
sha1 = { version = "0.10.6" }
sha2 = "0.10"
strum = { version = "0.26", features = ["derive"] }
time = "0.3.41"
unicode-normalization = "0.1.24"
utoipa = { version = "4.2.3", features = ["preserve_order", "preserve_path_order", "time"] }
url = "2.5.4"
urlencoding = "2.1.3"
uuid = { version = "1.17.0", features = ["v4"] }

# First party crates
api_models = { version = "0.1.0", path = "../api_models", features = ["errors"], default-features = false }
cards = { version = "0.1.0", path = "../cards" }
common_enums = { version = "0.1.0", path = "../common_enums" }
common_types = { version = "0.1.0", path = "../common_types" }
common_utils = { version = "0.1.0", path = "../common_utils", features = ["async_ext", "logs", "metrics", "crypto_openssl"] }
hyperswitch_domain_models = { version = "0.1.0", path = "../hyperswitch_domain_models", default-features = false }
hyperswitch_interfaces = { version = "0.1.0", path = "../hyperswitch_interfaces", default-features = false }
masking = { version = "0.1.0", path = "../masking" }
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] }

[lints]
workspace = true


// File: crates/hyperswitch_connectors/src/types.rs

#[cfg(feature = "v2")]
use hyperswitch_domain_models::router_data_v2::RouterDataV2;
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::types::{PayoutsData, PayoutsResponseData};
use hyperswitch_domain_models::{
    router_data::{AccessToken, RouterData},
    router_flow_types::{
        authentication::{
            Authentication, PostAuthentication, PreAuthentication, PreAuthenticationVersionCall,
        },
        Accept, AccessTokenAuth, Authorize, Capture, CreateOrder, Defend, Dsync, Evidence,
        ExtendAuthorization, Fetch, PSync, PostProcessing, PreProcessing, Retrieve, Session,
        Upload, Void,
    },
    router_request_types::{
        authentication::{
            ConnectorAuthenticationRequestData, ConnectorPostAuthenticationRequestData,
            PreAuthNRequestData,
        },
        AcceptDisputeRequestData, AccessTokenRequestData, CreateOrderRequestData,
        DefendDisputeRequestData, DisputeSyncData, FetchDisputesRequestData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsExtendAuthorizationData,
        PaymentsPostProcessingData, PaymentsPreProcessingData, PaymentsSessionData,
        PaymentsSyncData, RefundsData, RetrieveFileRequestData, SubmitEvidenceRequestData,
        UploadFileRequestData,
    },
    router_response_types::{
        AcceptDisputeResponse, AuthenticationResponseData, DefendDisputeResponse,
        DisputeSyncResponse, FetchDisputesResponse, PaymentsResponseData, RefundsResponseData,
        RetrieveFileResponse, SubmitEvidenceResponse, UploadFileResponse,
    },
};
#[cfg(feature = "frm")]
use hyperswitch_domain_models::{
    router_flow_types::{Checkout, Fulfillment, RecordReturn, Sale, Transaction},
    router_request_types::fraud_check::{
        FraudCheckCheckoutData, FraudCheckFulfillmentData, FraudCheckRecordReturnData,
        FraudCheckSaleData, FraudCheckTransactionData,
    },
    router_response_types::fraud_check::FraudCheckResponseData,
};
use hyperswitch_interfaces::api::ConnectorIntegration;

pub(crate) type PaymentsSyncResponseRouterData<R> =
    ResponseRouterData<PSync, R, PaymentsSyncData, PaymentsResponseData>;
pub(crate) type PaymentsResponseRouterData<R> =
    ResponseRouterData<Authorize, R, PaymentsAuthorizeData, PaymentsResponseData>;
pub(crate) type PaymentsCaptureResponseRouterData<R> =
    ResponseRouterData<Capture, R, PaymentsCaptureData, PaymentsResponseData>;
pub(crate) type RefundsResponseRouterData<F, R> =
    ResponseRouterData<F, R, RefundsData, RefundsResponseData>;
pub(crate) type RefreshTokenRouterData =
    RouterData<AccessTokenAuth, AccessTokenRequestData, AccessToken>;

pub(crate) type PaymentsCancelResponseRouterData<R> =
    ResponseRouterData<Void, R, PaymentsCancelData, PaymentsResponseData>;
pub(crate) type PaymentsPreprocessingResponseRouterData<R> =
    ResponseRouterData<PreProcessing, R, PaymentsPreProcessingData, PaymentsResponseData>;
pub(crate) type PaymentsSessionResponseRouterData<R> =
    ResponseRouterData<Session, R, PaymentsSessionData, PaymentsResponseData>;
pub(crate) type CreateOrderResponseRouterData<R> =
    ResponseRouterData<CreateOrder, R, CreateOrderRequestData, PaymentsResponseData>;
pub(crate) type PaymentsExtendAuthorizationResponseRouterData<R> = ResponseRouterData<
    ExtendAuthorization,
    R,
    PaymentsExtendAuthorizationData,
    PaymentsResponseData,
>;

pub(crate) type AcceptDisputeRouterData =
    RouterData<Accept, AcceptDisputeRequestData, AcceptDisputeResponse>;
pub(crate) type SubmitEvidenceRouterData =
    RouterData<Evidence, SubmitEvidenceRequestData, SubmitEvidenceResponse>;
pub(crate) type UploadFileRouterData =
    RouterData<Upload, UploadFileRequestData, UploadFileResponse>;
pub(crate) type DefendDisputeRouterData =
    RouterData<Defend, DefendDisputeRequestData, DefendDisputeResponse>;
pub(crate) type FetchDisputeRouterData =
    RouterData<Fetch, FetchDisputesRequestData, FetchDisputesResponse>;
pub(crate) type DisputeSyncRouterData = RouterData<Dsync, DisputeSyncData, DisputeSyncResponse>;

#[cfg(feature = "payouts")]
pub(crate) type PayoutsResponseRouterData<F, R> =
    ResponseRouterData<F, R, PayoutsData, PayoutsResponseData>;

// TODO: Remove `ResponseRouterData` from router crate after all the related type aliases are moved to this crate.
pub(crate) struct ResponseRouterData<Flow, R, Request, Response> {
    pub(crate) response: R,
    pub(crate) data: RouterData<Flow, Request, Response>,
    pub(crate) http_code: u16,
}
#[cfg(feature = "frm")]
pub(crate) type FrmFulfillmentRouterData =
    RouterData<Fulfillment, FraudCheckFulfillmentData, FraudCheckResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmCheckoutType =
    dyn ConnectorIntegration<Checkout, FraudCheckCheckoutData, FraudCheckResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmTransactionType =
    dyn ConnectorIntegration<Transaction, FraudCheckTransactionData, FraudCheckResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmTransactionRouterData =
    RouterData<Transaction, FraudCheckTransactionData, FraudCheckResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmFulfillmentType =
    dyn ConnectorIntegration<Fulfillment, FraudCheckFulfillmentData, FraudCheckResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmCheckoutRouterData =
    RouterData<Checkout, FraudCheckCheckoutData, FraudCheckResponseData>;
#[cfg(feature = "v2")]
pub(crate) struct ResponseRouterDataV2<Flow, R, ResourceCommonData, Request, Response> {
    pub response: R,
    pub data: RouterDataV2<Flow, ResourceCommonData, Request, Response>,
    #[allow(dead_code)] // Used for metadata passing but this is not read
    pub http_code: u16,
}

pub(crate) type PreAuthNRouterData =
    RouterData<PreAuthentication, PreAuthNRequestData, AuthenticationResponseData>;
pub(crate) type PreAuthNVersionCallRouterData =
    RouterData<PreAuthenticationVersionCall, PreAuthNRequestData, AuthenticationResponseData>;
pub(crate) type ConnectorAuthenticationRouterData =
    RouterData<Authentication, ConnectorAuthenticationRequestData, AuthenticationResponseData>;
pub(crate) type ConnectorPostAuthenticationRouterData = RouterData<
    PostAuthentication,
    ConnectorPostAuthenticationRequestData,
    AuthenticationResponseData,
>;
pub(crate) type ConnectorAuthenticationType = dyn ConnectorIntegration<
    Authentication,
    ConnectorAuthenticationRequestData,
    AuthenticationResponseData,
>;
pub(crate) type ConnectorPostAuthenticationType = dyn ConnectorIntegration<
    PostAuthentication,
    ConnectorPostAuthenticationRequestData,
    AuthenticationResponseData,
>;
pub(crate) type ConnectorPreAuthenticationType =
    dyn ConnectorIntegration<PreAuthentication, PreAuthNRequestData, AuthenticationResponseData>;
pub(crate) type ConnectorPreAuthenticationVersionCallType = dyn ConnectorIntegration<
    PreAuthenticationVersionCall,
    PreAuthNRequestData,
    AuthenticationResponseData,
>;

pub(crate) type PaymentsPostProcessingRouterData =
    RouterData<PostProcessing, PaymentsPostProcessingData, PaymentsResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmSaleRouterData = RouterData<Sale, FraudCheckSaleData, FraudCheckResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmRecordReturnRouterData =
    RouterData<RecordReturn, FraudCheckRecordReturnData, FraudCheckResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmRecordReturnType =
    dyn ConnectorIntegration<RecordReturn, FraudCheckRecordReturnData, FraudCheckResponseData>;
#[cfg(feature = "frm")]
pub(crate) type FrmSaleType =
    dyn ConnectorIntegration<Sale, FraudCheckSaleData, FraudCheckResponseData>;

pub(crate) type RetrieveFileRouterData =
    RouterData<Retrieve, RetrieveFileRequestData, RetrieveFileResponse>;

#[cfg(feature = "payouts")]
pub(crate) trait PayoutIndividualDetailsExt {
    type Error;
    fn get_external_account_account_holder_type(&self) -> Result<String, Self::Error>;
}

#[cfg(feature = "payouts")]
impl PayoutIndividualDetailsExt for api_models::payouts::PayoutIndividualDetails {
    type Error = error_stack::Report<hyperswitch_interfaces::errors::ConnectorError>;
    fn get_external_account_account_holder_type(&self) -> Result<String, Self::Error> {
        self.external_account_account_holder_type
            .clone()
            .ok_or_else(crate::utils::missing_field_err(
                "external_account_account_holder_type",
            ))
    }
}