// File: crates/router/src/types/storage/refund.rs
// Module: router

use api_models::payments::AmountFilter;
use async_bb8_diesel::AsyncRunQueryDsl;
use common_utils::errors::CustomResult;
use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods, QueryDsl};
#[cfg(feature = "v1")]
use diesel_models::schema::refund::dsl;
#[cfg(feature = "v2")]
use diesel_models::schema_v2::refund::dsl;
use diesel_models::{
    enums::{Currency, RefundStatus},
    errors,
    query::generics::db_metrics,
    refund::Refund,
};
use error_stack::ResultExt;
use hyperswitch_domain_models::refunds;

use crate::{connection::PgPooledConn, logger};

#[async_trait::async_trait]
pub trait RefundDbExt: Sized {
    #[cfg(feature = "v1")]
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &refunds::RefundListConstraints,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError>;

    #[cfg(feature = "v2")]
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: refunds::RefundListConstraints,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError>;

    #[cfg(feature = "v1")]
    async fn filter_by_meta_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &common_utils::types::TimeRange,
    ) -> CustomResult<api_models::refunds::RefundListMetaData, errors::DatabaseError>;

    #[cfg(feature = "v1")]
    async fn get_refunds_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &refunds::RefundListConstraints,
    ) -> CustomResult<i64, errors::DatabaseError>;

    #[cfg(feature = "v1")]
    async fn get_refund_status_with_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
        time_range: &common_utils::types::TimeRange,
    ) -> CustomResult<Vec<(RefundStatus, i64)>, errors::DatabaseError>;

    #[cfg(feature = "v2")]
    async fn get_refunds_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: refunds::RefundListConstraints,
    ) -> CustomResult<i64, errors::DatabaseError>;
}

#[async_trait::async_trait]
impl RefundDbExt for Refund {
    #[cfg(feature = "v1")]
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &refunds::RefundListConstraints,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .order(dsl::modified_at.desc())
            .into_boxed();
        let mut search_by_pay_or_ref_id = false;

        if let (Some(pid), Some(ref_id)) = (
            &refund_list_details.payment_id,
            &refund_list_details.refund_id,
        ) {
            search_by_pay_or_ref_id = true;
            filter = filter
                .filter(
                    dsl::payment_id
                        .eq(pid.to_owned())
                        .or(dsl::refund_id.eq(ref_id.to_owned())),
                )
                .limit(limit)
                .offset(offset);
        };

        if !search_by_pay_or_ref_id {
            match &refund_list_details.payment_id {
                Some(pid) => {
                    filter = filter.filter(dsl::payment_id.eq(pid.to_owned()));
                }
                None => {
                    filter = filter.limit(limit).offset(offset);
                }
            };
        }
        if !search_by_pay_or_ref_id {
            match &refund_list_details.refund_id {
                Some(ref_id) => {
                    filter = filter.filter(dsl::refund_id.eq(ref_id.to_owned()));
                }
                None => {
                    filter = filter.limit(limit).offset(offset);
                }
            };
        }
        match &refund_list_details.profile_id {
            Some(profile_id) => {
                filter = filter
                    .filter(dsl::profile_id.eq_any(profile_id.to_owned()))
                    .limit(limit)
                    .offset(offset);
            }
            None => {
                filter = filter.limit(limit).offset(offset);
            }
        };

        if let Some(time_range) = refund_list_details.time_range {
            filter = filter.filter(dsl::created_at.ge(time_range.start_time));

            if let Some(end_time) = time_range.end_time {
                filter = filter.filter(dsl::created_at.le(end_time));
            }
        }

        filter = match refund_list_details.amount_filter {
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.between(start, end)),
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: None,
            }) => filter.filter(dsl::refund_amount.ge(start)),
            Some(AmountFilter {
                start_amount: None,
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.le(end)),
            _ => filter,
        };

        if let Some(connector) = refund_list_details.connector.clone() {
            filter = filter.filter(dsl::connector.eq_any(connector));
        }

        if let Some(merchant_connector_id) = refund_list_details.merchant_connector_id.clone() {
            filter = filter.filter(dsl::merchant_connector_id.eq_any(merchant_connector_id));
        }

        if let Some(filter_currency) = &refund_list_details.currency {
            filter = filter.filter(dsl::currency.eq_any(filter_currency.clone()));
        }

        if let Some(filter_refund_status) = &refund_list_details.refund_status {
            filter = filter.filter(dsl::refund_status.eq_any(filter_refund_status.clone()));
        }

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
            filter.get_results_async(conn),
            db_metrics::DatabaseOperation::Filter,
        )
        .await
        .change_context(errors::DatabaseError::NotFound)
        .attach_printable_lazy(|| "Error filtering records by predicate")
    }

    #[cfg(feature = "v2")]
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: refunds::RefundListConstraints,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .order(dsl::modified_at.desc())
            .into_boxed();

        if let Some(payment_id) = &refund_list_details.payment_id {
            filter = filter.filter(dsl::payment_id.eq(payment_id.to_owned()));
        }

        if let Some(refund_id) = &refund_list_details.refund_id {
            filter = filter.filter(dsl::id.eq(refund_id.to_owned()));
        }

        if let Some(time_range) = &refund_list_details.time_range {
            filter = filter.filter(dsl::created_at.ge(time_range.start_time));

            if let Some(end_time) = time_range.end_time {
                filter = filter.filter(dsl::created_at.le(end_time));
            }
        }

        filter = match refund_list_details.amount_filter {
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.between(start, end)),
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: None,
            }) => filter.filter(dsl::refund_amount.ge(start)),
            Some(AmountFilter {
                start_amount: None,
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.le(end)),
            _ => filter,
        };

        if let Some(connector) = refund_list_details.connector {
            filter = filter.filter(dsl::connector.eq_any(connector));
        }

        if let Some(connector_id_list) = refund_list_details.connector_id_list {
            filter = filter.filter(dsl::connector_id.eq_any(connector_id_list));
        }

        if let Some(filter_currency) = refund_list_details.currency {
            filter = filter.filter(dsl::currency.eq_any(filter_currency));
        }

        if let Some(filter_refund_status) = refund_list_details.refund_status {
            filter = filter.filter(dsl::refund_status.eq_any(filter_refund_status));
        }

        filter = filter.limit(limit).offset(offset);

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
            filter.get_results_async(conn),
            db_metrics::DatabaseOperation::Filter,
        )
        .await
        .change_context(errors::DatabaseError::NotFound)
        .attach_printable_lazy(|| "Error filtering records by predicate")

        // todo!()
    }

    #[cfg(feature = "v1")]
    async fn filter_by_meta_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &common_utils::types::TimeRange,
    ) -> CustomResult<api_models::refunds::RefundListMetaData, errors::DatabaseError> {
        let start_time = refund_list_details.start_time;

        let end_time = refund_list_details
            .end_time
            .unwrap_or_else(common_utils::date_time::now);

        let filter = <Self as HasTable>::table()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .order(dsl::modified_at.desc())
            .filter(dsl::created_at.ge(start_time))
            .filter(dsl::created_at.le(end_time));

        let filter_connector: Vec<String> = filter
            .clone()
            .select(dsl::connector)
            .distinct()
            .order_by(dsl::connector.asc())
            .get_results_async(conn)
            .await
            .change_context(errors::DatabaseError::Others)
            .attach_printable("Error filtering records by connector")?;

        let filter_currency: Vec<Currency> = filter
            .clone()
            .select(dsl::currency)
            .distinct()
            .order_by(dsl::currency.asc())
            .get_results_async(conn)
            .await
            .change_context(errors::DatabaseError::Others)
            .attach_printable("Error filtering records by currency")?;

        let filter_status: Vec<RefundStatus> = filter
            .select(dsl::refund_status)
            .distinct()
            .order_by(dsl::refund_status.asc())
            .get_results_async(conn)
            .await
            .change_context(errors::DatabaseError::Others)
            .attach_printable("Error filtering records by refund status")?;

        let meta = api_models::refunds::RefundListMetaData {
            connector: filter_connector,
            currency: filter_currency,
            refund_status: filter_status,
        };

        Ok(meta)
    }

    #[cfg(feature = "v1")]
    async fn get_refunds_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: &refunds::RefundListConstraints,
    ) -> CustomResult<i64, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .count()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .into_boxed();

        let mut search_by_pay_or_ref_id = false;

        if let (Some(pid), Some(ref_id)) = (
            &refund_list_details.payment_id,
            &refund_list_details.refund_id,
        ) {
            search_by_pay_or_ref_id = true;
            filter = filter.filter(
                dsl::payment_id
                    .eq(pid.to_owned())
                    .or(dsl::refund_id.eq(ref_id.to_owned())),
            );
        };

        if !search_by_pay_or_ref_id {
            if let Some(pay_id) = &refund_list_details.payment_id {
                filter = filter.filter(dsl::payment_id.eq(pay_id.to_owned()));
            }
        }

        if !search_by_pay_or_ref_id {
            if let Some(ref_id) = &refund_list_details.refund_id {
                filter = filter.filter(dsl::refund_id.eq(ref_id.to_owned()));
            }
        }
        if let Some(profile_id) = &refund_list_details.profile_id {
            filter = filter.filter(dsl::profile_id.eq_any(profile_id.to_owned()));
        }

        if let Some(time_range) = refund_list_details.time_range {
            filter = filter.filter(dsl::created_at.ge(time_range.start_time));

            if let Some(end_time) = time_range.end_time {
                filter = filter.filter(dsl::created_at.le(end_time));
            }
        }

        filter = match refund_list_details.amount_filter {
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.between(start, end)),
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: None,
            }) => filter.filter(dsl::refund_amount.ge(start)),
            Some(AmountFilter {
                start_amount: None,
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.le(end)),
            _ => filter,
        };

        if let Some(connector) = refund_list_details.connector.clone() {
            filter = filter.filter(dsl::connector.eq_any(connector));
        }

        if let Some(merchant_connector_id) = refund_list_details.merchant_connector_id.clone() {
            filter = filter.filter(dsl::merchant_connector_id.eq_any(merchant_connector_id))
        }

        if let Some(filter_currency) = &refund_list_details.currency {
            filter = filter.filter(dsl::currency.eq_any(filter_currency.clone()));
        }

        if let Some(filter_refund_status) = &refund_list_details.refund_status {
            filter = filter.filter(dsl::refund_status.eq_any(filter_refund_status.clone()));
        }

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        filter
            .get_result_async::<i64>(conn)
            .await
            .change_context(errors::DatabaseError::NotFound)
            .attach_printable_lazy(|| "Error filtering count of refunds")
    }

    #[cfg(feature = "v2")]
    async fn get_refunds_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_list_details: refunds::RefundListConstraints,
    ) -> CustomResult<i64, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .count()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .into_boxed();

        if let Some(payment_id) = &refund_list_details.payment_id {
            filter = filter.filter(dsl::payment_id.eq(payment_id.to_owned()));
        }

        if let Some(refund_id) = &refund_list_details.refund_id {
            filter = filter.filter(dsl::id.eq(refund_id.to_owned()));
        }

        if let Some(time_range) = refund_list_details.time_range {
            filter = filter.filter(dsl::created_at.ge(time_range.start_time));

            if let Some(end_time) = time_range.end_time {
                filter = filter.filter(dsl::created_at.le(end_time));
            }
        }

        filter = match refund_list_details.amount_filter {
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.between(start, end)),
            Some(AmountFilter {
                start_amount: Some(start),
                end_amount: None,
            }) => filter.filter(dsl::refund_amount.ge(start)),
            Some(AmountFilter {
                start_amount: None,
                end_amount: Some(end),
            }) => filter.filter(dsl::refund_amount.le(end)),
            _ => filter,
        };

        if let Some(connector) = refund_list_details.connector {
            filter = filter.filter(dsl::connector.eq_any(connector));
        }

        if let Some(connector_id_list) = refund_list_details.connector_id_list {
            filter = filter.filter(dsl::connector_id.eq_any(connector_id_list));
        }

        if let Some(filter_currency) = refund_list_details.currency {
            filter = filter.filter(dsl::currency.eq_any(filter_currency));
        }

        if let Some(filter_refund_status) = refund_list_details.refund_status {
            filter = filter.filter(dsl::refund_status.eq_any(filter_refund_status));
        }

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        filter
            .get_result_async::<i64>(conn)
            .await
            .change_context(errors::DatabaseError::NotFound)
            .attach_printable_lazy(|| "Error filtering count of refunds")
    }

    #[cfg(feature = "v1")]
    async fn get_refund_status_with_count(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
        time_range: &common_utils::types::TimeRange,
    ) -> CustomResult<Vec<(RefundStatus, i64)>, errors::DatabaseError> {
        let mut query = <Self as HasTable>::table()
            .group_by(dsl::refund_status)
            .select((dsl::refund_status, diesel::dsl::count_star()))
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .into_boxed();

        if let Some(profile_id) = profile_id_list {
            query = query.filter(dsl::profile_id.eq_any(profile_id));
        }

        query = query.filter(dsl::created_at.ge(time_range.start_time));

        query = match time_range.end_time {
            Some(ending_at) => query.filter(dsl::created_at.le(ending_at)),
            None => query,
        };

        logger::debug!(filter = %diesel::debug_query::<diesel::pg::Pg,_>(&query).to_string());

        db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
            query.get_results_async::<(RefundStatus, i64)>(conn),
            db_metrics::DatabaseOperation::Count,
        )
        .await
        .change_context(errors::DatabaseError::NotFound)
        .attach_printable_lazy(|| "Error filtering status count of refunds")
    }
}


// Implementation: impl GenericLink
// File: crates/diesel_models/src/query/generic_link.rs
// Module: diesel_models
// Methods: 3 total (0 public)

impl GenericLink


// Function: get_role_from_token
// File: crates/router/src/routes/user_role.rs
// Module: router

pub fn get_role_from_token(state: web::Data<AppState>, req: HttpRequest) -> HttpResponse


// File: crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs
// Module: hyperswitch_connectors
// Public functions: 1
// Public structs: 34

use std::str::FromStr;

use common_enums::enums::CaptureMethod;
use common_utils::types::MinorUnit;
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{AccessToken, ConnectorAuthType, RouterData},
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::{PaymentsCancelData, ResponseId},
    router_response_types::{PaymentsResponseData, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        RefreshTokenRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::errors;
use masking::{PeekInterface, Secret};
use serde::{Deserialize, Serialize};

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

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

#[derive(Debug, Clone, Serialize)]
pub struct JpmorganAuthUpdateRequest {
    pub grant_type: String,
    pub scope: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct JpmorganAuthUpdateResponse {
    pub access_token: Secret<String>,
    pub scope: String,
    pub token_type: String,
    pub expires_in: i64,
}

impl TryFrom<&RefreshTokenRouterData> for JpmorganAuthUpdateRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(_item: &RefreshTokenRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            grant_type: String::from("client_credentials"),
            scope: String::from("jpm:payments:sandbox"),
        })
    }
}

impl<F, T> TryFrom<ResponseRouterData<F, JpmorganAuthUpdateResponse, T, AccessToken>>
    for RouterData<F, T, AccessToken>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, JpmorganAuthUpdateResponse, T, AccessToken>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(AccessToken {
                token: item.response.access_token,
                expires: item.response.expires_in,
            }),
            ..item.data
        })
    }
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganPaymentsRequest {
    capture_method: CapMethod,
    amount: MinorUnit,
    currency: common_enums::Currency,
    merchant: JpmorganMerchant,
    payment_method_type: JpmorganPaymentMethodType,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganCard {
    account_number: Secret<String>,
    expiry: Expiry,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganPaymentMethodType {
    card: JpmorganCard,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Expiry {
    month: Secret<i32>,
    year: Secret<i32>,
}

#[derive(Serialize, Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganMerchantSoftware {
    company_name: Secret<String>,
    product_name: Secret<String>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganMerchant {
    merchant_software: JpmorganMerchantSoftware,
}

fn map_capture_method(
    capture_method: CaptureMethod,
) -> Result<CapMethod, error_stack::Report<errors::ConnectorError>> {
    match capture_method {
        CaptureMethod::Automatic => Ok(CapMethod::Now),
        CaptureMethod::Manual => Ok(CapMethod::Manual),
        CaptureMethod::Scheduled
        | CaptureMethod::ManualMultiple
        | CaptureMethod::SequentialAutomatic => {
            Err(errors::ConnectorError::NotImplemented("Capture Method".to_string()).into())
        }
    }
}

impl TryFrom<&JpmorganRouterData<&PaymentsAuthorizeRouterData>> for JpmorganPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &JpmorganRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(req_card) => {
                if item.router_data.is_three_ds() {
                    return Err(errors::ConnectorError::NotSupported {
                        message: "3DS payments".to_string(),
                        connector: "Jpmorgan",
                    }
                    .into());
                }

                let capture_method =
                    map_capture_method(item.router_data.request.capture_method.unwrap_or_default());

                let merchant_software = JpmorganMerchantSoftware {
                    company_name: String::from("JPMC").into(),
                    product_name: String::from("Hyperswitch").into(),
                };

                let merchant = JpmorganMerchant { merchant_software };

                let expiry: Expiry = Expiry {
                    month: Secret::new(
                        req_card
                            .card_exp_month
                            .peek()
                            .clone()
                            .parse::<i32>()
                            .change_context(errors::ConnectorError::RequestEncodingFailed)?,
                    ),
                    year: req_card.get_expiry_year_as_4_digit_i32()?,
                };

                let account_number = Secret::new(req_card.card_number.to_string());

                let card = JpmorganCard {
                    account_number,
                    expiry,
                };

                let payment_method_type = JpmorganPaymentMethodType { card };

                Ok(Self {
                    capture_method: capture_method?,
                    currency: item.router_data.request.currency,
                    amount: item.amount,
                    merchant,
                    payment_method_type,
                })
            }
            PaymentMethodData::CardDetailsForNetworkTransactionId(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Wallet(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_) => Err(errors::ConnectorError::NotImplemented(
                get_unimplemented_payment_method_error_message("jpmorgan"),
            )
            .into()),
        }
    }
}

//JP Morgan uses access token only due to which we aren't reading the fields in this struct
#[derive(Debug)]
pub struct JpmorganAuthType {
    pub(super) _api_key: Secret<String>,
    pub(super) _key1: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for JpmorganAuthType {
    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 {
                _api_key: api_key.to_owned(),
                _key1: key1.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum JpmorganTransactionStatus {
    Success,
    Denied,
    Error,
}

#[derive(Default, Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "UPPERCASE")]
pub enum JpmorganTransactionState {
    Closed,
    Authorized,
    Voided,
    #[default]
    Pending,
    Declined,
    Error,
}

#[derive(Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganPaymentsResponse {
    transaction_id: String,
    request_id: String,
    transaction_state: JpmorganTransactionState,
    response_status: String,
    response_code: String,
    response_message: String,
    payment_method_type: PaymentMethodType,
    capture_method: Option<CapMethod>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Merchant {
    merchant_id: Option<String>,
    merchant_software: JpmorganMerchantSoftware,
    merchant_category_code: Option<String>,
}

#[derive(Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentMethodType {
    card: Option<Card>,
}

#[derive(Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Card {
    expiry: Option<ExpiryResponse>,
    card_type: Option<Secret<String>>,
    card_type_name: Option<Secret<String>>,
    masked_account_number: Option<Secret<String>>,
    card_type_indicators: Option<CardTypeIndicators>,
    network_response: Option<NetworkResponse>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NetworkResponse {
    address_verification_result: Option<Secret<String>>,
    address_verification_result_code: Option<Secret<String>>,
    card_verification_result_code: Option<Secret<String>>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExpiryResponse {
    month: Option<Secret<i32>>,
    year: Option<Secret<i32>>,
}

#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CardTypeIndicators {
    issuance_country_code: Option<Secret<String>>,
    is_durbin_regulated: Option<bool>,
    card_product_types: Secret<Vec<String>>,
}

pub fn attempt_status_from_transaction_state(
    transaction_state: JpmorganTransactionState,
) -> common_enums::AttemptStatus {
    match transaction_state {
        JpmorganTransactionState::Authorized => common_enums::AttemptStatus::Authorized,
        JpmorganTransactionState::Closed => common_enums::AttemptStatus::Charged,
        JpmorganTransactionState::Declined | JpmorganTransactionState::Error => {
            common_enums::AttemptStatus::Failure
        }
        JpmorganTransactionState::Pending => common_enums::AttemptStatus::Pending,
        JpmorganTransactionState::Voided => common_enums::AttemptStatus::Voided,
    }
}

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

    fn try_from(
        item: ResponseRouterData<F, JpmorganPaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        let transaction_state = match item.response.transaction_state {
            JpmorganTransactionState::Closed => match item.response.capture_method {
                Some(CapMethod::Now) => JpmorganTransactionState::Closed,
                _ => JpmorganTransactionState::Authorized,
            },
            JpmorganTransactionState::Authorized => JpmorganTransactionState::Authorized,
            JpmorganTransactionState::Voided => JpmorganTransactionState::Voided,
            JpmorganTransactionState::Pending => JpmorganTransactionState::Pending,
            JpmorganTransactionState::Declined => JpmorganTransactionState::Declined,
            JpmorganTransactionState::Error => JpmorganTransactionState::Error,
        };
        let status = attempt_status_from_transaction_state(transaction_state);

        Ok(Self {
            status,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_id.clone(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.transaction_id.clone()),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganCaptureRequest {
    capture_method: Option<CapMethod>,
    amount: MinorUnit,
    currency: Option<common_enums::Currency>,
}

#[derive(Debug, Default, Copy, Serialize, Deserialize, Clone)]
#[serde(rename_all = "UPPERCASE")]
pub enum CapMethod {
    #[default]
    Now,
    Delayed,
    Manual,
}

impl TryFrom<&JpmorganRouterData<&PaymentsCaptureRouterData>> for JpmorganCaptureRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &JpmorganRouterData<&PaymentsCaptureRouterData>,
    ) -> Result<Self, Self::Error> {
        let capture_method = Some(map_capture_method(
            item.router_data.request.capture_method.unwrap_or_default(),
        )?);
        Ok(Self {
            capture_method,
            amount: item.amount,
            currency: Some(item.router_data.request.currency),
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganCaptureResponse {
    pub transaction_id: String,
    pub request_id: String,
    pub transaction_state: JpmorganTransactionState,
    pub response_status: JpmorganTransactionStatus,
    pub response_code: String,
    pub response_message: String,
    pub payment_method_type: PaymentMethodTypeCapRes,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentMethodTypeCapRes {
    pub card: Option<CardCapRes>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CardCapRes {
    pub card_type: Option<Secret<String>>,
    pub card_type_name: Option<Secret<String>>,
    unmasked_account_number: Option<Secret<String>>,
}

impl<F, T> TryFrom<ResponseRouterData<F, JpmorganCaptureResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, JpmorganCaptureResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        let status = attempt_status_from_transaction_state(item.response.transaction_state);
        Ok(Self {
            status,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_id.clone(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.transaction_id.clone()),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganPSyncResponse {
    transaction_id: String,
    transaction_state: JpmorganTransactionState,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum JpmorganResponseStatus {
    Success,
    Denied,
    Error,
}

impl<F, PaymentsSyncData>
    TryFrom<ResponseRouterData<F, JpmorganPSyncResponse, PaymentsSyncData, PaymentsResponseData>>
    for RouterData<F, PaymentsSyncData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, JpmorganPSyncResponse, PaymentsSyncData, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        let status = attempt_status_from_transaction_state(item.response.transaction_state);
        Ok(Self {
            status,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_id.clone(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.transaction_id.clone()),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TransactionData {
    payment_type: Option<Secret<String>>,
    status_code: Secret<i32>,
    txn_secret: Option<Secret<String>>,
    tid: Option<Secret<i64>>,
    test_mode: Option<Secret<i8>>,
    status: Option<JpmorganTransactionStatus>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganRefundRequest {
    pub merchant: MerchantRefundReq,
    pub amount: MinorUnit,
    pub currency: common_enums::Currency,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MerchantRefundReq {
    pub merchant_software: JpmorganMerchantSoftware,
}

impl<F> TryFrom<&JpmorganRouterData<&RefundsRouterData<F>>> for JpmorganRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &JpmorganRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        let merchant_software = JpmorganMerchantSoftware {
            company_name: String::from("JPMC").into(),
            product_name: String::from("Hyperswitch").into(),
        };
        let merchant = MerchantRefundReq { merchant_software };
        let amount = item.amount;
        let currency = item.router_data.request.currency;

        Ok(Self {
            merchant,
            amount,
            currency,
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganRefundResponse {
    pub transaction_id: Option<String>,
    pub request_id: String,
    pub transaction_state: JpmorganTransactionState,
    pub amount: MinorUnit,
    pub currency: common_enums::Currency,
    pub response_status: JpmorganResponseStatus,
    pub response_code: String,
    pub response_message: String,
    pub transaction_reference_id: Option<String>,
    pub remaining_refundable_amount: Option<i64>,
}

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

impl From<RefundStatus> for common_enums::RefundStatus {
    fn from(item: RefundStatus) -> Self {
        match item {
            RefundStatus::Succeeded => Self::Success,
            RefundStatus::Failed => Self::Failure,
            RefundStatus::Processing => Self::Pending,
        }
    }
}

impl From<(JpmorganResponseStatus, JpmorganTransactionState)> for RefundStatus {
    fn from(
        (response_status, transaction_state): (JpmorganResponseStatus, JpmorganTransactionState),
    ) -> Self {
        match response_status {
            JpmorganResponseStatus::Success => match transaction_state {
                JpmorganTransactionState::Voided | JpmorganTransactionState::Closed => {
                    Self::Succeeded
                }
                JpmorganTransactionState::Declined | JpmorganTransactionState::Error => {
                    Self::Failed
                }
                JpmorganTransactionState::Pending | JpmorganTransactionState::Authorized => {
                    Self::Processing
                }
            },
            JpmorganResponseStatus::Denied | JpmorganResponseStatus::Error => Self::Failed,
        }
    }
}

impl TryFrom<RefundsResponseRouterData<Execute, JpmorganRefundResponse>>
    for RefundsRouterData<Execute>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, JpmorganRefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item
                    .response
                    .transaction_id
                    .clone()
                    .ok_or(errors::ConnectorError::ResponseHandlingFailed)?,
                refund_status: RefundStatus::from((
                    item.response.response_status,
                    item.response.transaction_state,
                ))
                .into(),
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganRefundSyncResponse {
    transaction_id: String,
    request_id: String,
    transaction_state: JpmorganTransactionState,
    amount: MinorUnit,
    currency: common_enums::Currency,
    response_status: JpmorganResponseStatus,
    response_code: String,
}

impl TryFrom<RefundsResponseRouterData<RSync, JpmorganRefundSyncResponse>>
    for RefundsRouterData<RSync>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, JpmorganRefundSyncResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.transaction_id.clone(),
                refund_status: RefundStatus::from((
                    item.response.response_status,
                    item.response.transaction_state,
                ))
                .into(),
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ReversalReason {
    NoResponse,
    LateResponse,
    UnableToDeliver,
    CardDeclined,
    MacNotVerified,
    MacSyncError,
    ZekSyncError,
    SystemMalfunction,
    SuspectedFraud,
}

impl FromStr for ReversalReason {
    type Err = error_stack::Report<errors::ConnectorError>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "NO_RESPONSE" => Ok(Self::NoResponse),
            "LATE_RESPONSE" => Ok(Self::LateResponse),
            "UNABLE_TO_DELIVER" => Ok(Self::UnableToDeliver),
            "CARD_DECLINED" => Ok(Self::CardDeclined),
            "MAC_NOT_VERIFIED" => Ok(Self::MacNotVerified),
            "MAC_SYNC_ERROR" => Ok(Self::MacSyncError),
            "ZEK_SYNC_ERROR" => Ok(Self::ZekSyncError),
            "SYSTEM_MALFUNCTION" => Ok(Self::SystemMalfunction),
            "SUSPECTED_FRAUD" => Ok(Self::SuspectedFraud),
            _ => Err(report!(errors::ConnectorError::InvalidDataFormat {
                field_name: "cancellation_reason",
            })),
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganCancelRequest {
    pub amount: Option<i64>,
    pub is_void: Option<bool>,
    pub reversal_reason: Option<ReversalReason>,
}

impl TryFrom<JpmorganRouterData<&PaymentsCancelRouterData>> for JpmorganCancelRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: JpmorganRouterData<&PaymentsCancelRouterData>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.router_data.request.amount,
            is_void: Some(true),
            reversal_reason: item
                .router_data
                .request
                .cancellation_reason
                .as_ref()
                .map(|reason| ReversalReason::from_str(reason))
                .transpose()?,
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganCancelResponse {
    transaction_id: String,
    request_id: String,
    response_status: JpmorganResponseStatus,
    response_code: String,
    response_message: String,
    payment_method_type: JpmorganPaymentMethodTypeCancelResponse,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganPaymentMethodTypeCancelResponse {
    pub card: CardCancelResponse,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CardCancelResponse {
    pub card_type: Secret<String>,
    pub card_type_name: Secret<String>,
}

impl<F>
    TryFrom<ResponseRouterData<F, JpmorganCancelResponse, PaymentsCancelData, PaymentsResponseData>>
    for RouterData<F, PaymentsCancelData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            JpmorganCancelResponse,
            PaymentsCancelData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let status = match item.response.response_status {
            JpmorganResponseStatus::Success => common_enums::AttemptStatus::Voided,
            JpmorganResponseStatus::Denied | JpmorganResponseStatus::Error => {
                common_enums::AttemptStatus::Failure
            }
        };
        Ok(Self {
            status,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_id.clone(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.transaction_id.clone()),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganValidationErrors {
    pub code: Option<String>,
    pub message: Option<String>,
    pub entity: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganErrorInformation {
    pub code: Option<String>,
    pub message: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct JpmorganErrorResponse {
    pub response_status: JpmorganTransactionStatus,
    pub response_code: String,
    pub response_message: Option<String>,
}


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

pub fn get_decrypted_vault_response_payload(
    jwekey: &settings::Jwekey,
    jwe_body: encryption::JweBody,
    decryption_scheme: settings::DecryptionScheme,
) -> CustomResult<String, errors::VaultError>


// Function: is_network_token_payment_method_data
// File: crates/hyperswitch_domain_models/src/payment_method_data.rs
// Module: hyperswitch_domain_models

pub fn is_network_token_payment_method_data(&self) -> bool


// Implementation: impl IncomingWebhook for for DummyConnector
// File: crates/hyperswitch_connectors/src/connectors/dummyconnector.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl IncomingWebhook for for DummyConnector


// Implementation: impl api::ConnectorAccessToken for for HyperswitchVault
// File: crates/hyperswitch_connectors/src/connectors/hyperswitch_vault.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for HyperswitchVault


// Struct: OpensearchHit
// File: crates/api_models/src/analytics/search.rs
// Module: api_models
// Implementations: 0

pub struct OpensearchHit


// Function: from_storage
// File: crates/router/src/services/kafka/refund.rs
// Module: router

pub fn from_storage(refund: &'a Refund) -> Self


// Struct: AirwallexCardPaymentOptions
// File: crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AirwallexCardPaymentOptions


// Struct: LoonioRefundRequest
// File: crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct LoonioRefundRequest


// Struct: RedsysThreeDsInvokeData
// File: crates/hyperswitch_connectors/src/connectors/redsys/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RedsysThreeDsInvokeData


// Implementation: impl ApiKeyId
// File: crates/common_utils/src/id_type/api_key.rs
// Module: common_utils
// Methods: 1 total (1 public)

impl ApiKeyId


// Struct: NovalnetMandate
// File: crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NovalnetMandate


// Implementation: impl MessagingInterface for for EventsHandler
// File: crates/router/src/events.rs
// Module: router
// Methods: 1 total (0 public)

impl MessagingInterface for for EventsHandler


// Struct: CheckoutDisputeWebhookBody
// File: crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CheckoutDisputeWebhookBody


// File: crates/router/src/utils/ext_traits.rs
// Module: router

pub use hyperswitch_domain_models::ext_traits::OptionExt;

use crate::core::errors::{self, CustomResult};

pub trait ValidateCall<T, F> {
    fn validate_opt(self, func: F) -> CustomResult<(), errors::ValidationError>;
}

impl<T, F> ValidateCall<T, F> for Option<&T>
where
    F: Fn(&T) -> CustomResult<(), errors::ValidationError>,
{
    fn validate_opt(self, func: F) -> CustomResult<(), errors::ValidationError> {
        match self {
            Some(val) => func(val),
            None => Ok(()),
        }
    }
}


// File: crates/router/src/types/api/verify_connector.rs
// Module: router
// Public structs: 1

pub mod paypal;
pub mod stripe;
use error_stack::ResultExt;

use crate::{
    consts,
    core::errors,
    services::{
        self,
        connector_integration_interface::{BoxedConnectorIntegrationInterface, ConnectorEnum},
    },
    types::{self, api, api::ConnectorCommon, domain, storage::enums as storage_enums},
    SessionState,
};

#[derive(Clone)]
pub struct VerifyConnectorData {
    pub connector: ConnectorEnum,
    pub connector_auth: types::ConnectorAuthType,
    pub card_details: domain::Card,
}

impl VerifyConnectorData {
    fn get_payment_authorize_data(&self) -> types::PaymentsAuthorizeData {
        types::PaymentsAuthorizeData {
            payment_method_data: domain::PaymentMethodData::Card(self.card_details.clone()),
            email: None,
            customer_name: None,
            amount: 1000,
            minor_amount: common_utils::types::MinorUnit::new(1000),
            confirm: true,
            order_tax_amount: None,
            currency: storage_enums::Currency::USD,
            metadata: None,
            mandate_id: None,
            webhook_url: None,
            customer_id: None,
            off_session: None,
            browser_info: None,
            session_token: None,
            order_details: None,
            order_category: None,
            capture_method: None,
            enrolled_for_3ds: false,
            router_return_url: None,
            surcharge_details: None,
            setup_future_usage: None,
            payment_experience: None,
            payment_method_type: None,
            statement_descriptor: None,
            setup_mandate_details: None,
            complete_authorize_url: None,
            related_transaction_id: None,
            statement_descriptor_suffix: None,
            request_extended_authorization: None,
            request_incremental_authorization: false,
            authentication_data: None,
            customer_acceptance: None,
            split_payments: None,
            merchant_order_reference_id: None,
            integrity_object: None,
            additional_payment_method_data: None,
            shipping_cost: None,
            merchant_account_id: None,
            merchant_config_currency: None,
            connector_testing_data: None,
            order_id: None,
            locale: None,
            payment_channel: None,
            enable_partial_authorization: None,
            enable_overcapture: None,
            is_stored_credential: None,
        }
    }

    fn get_router_data<F, R1, R2>(
        &self,
        state: &SessionState,
        request_data: R1,
        access_token: Option<types::AccessToken>,
    ) -> types::RouterData<F, R1, R2> {
        let attempt_id =
            common_utils::generate_id_with_default_len(consts::VERIFY_CONNECTOR_ID_PREFIX);
        types::RouterData {
            flow: std::marker::PhantomData,
            status: storage_enums::AttemptStatus::Started,
            request: request_data,
            response: Err(errors::ApiErrorResponse::InternalServerError.into()),
            connector: self.connector.id().to_string(),
            auth_type: storage_enums::AuthenticationType::NoThreeDs,
            test_mode: None,
            attempt_id: attempt_id.clone(),
            description: None,
            customer_id: None,
            tenant_id: state.tenant.tenant_id.clone(),
            merchant_id: common_utils::id_type::MerchantId::default(),
            reference_id: None,
            access_token,
            session_token: None,
            payment_method: storage_enums::PaymentMethod::Card,
            amount_captured: None,
            minor_amount_captured: None,
            preprocessing_id: None,
            connector_customer: None,
            connector_auth_type: self.connector_auth.clone(),
            connector_meta_data: None,
            connector_wallets_details: None,
            payment_method_token: None,
            connector_api_version: None,
            recurring_mandate_payment_data: None,
            payment_method_status: None,
            connector_request_reference_id: attempt_id,
            address: types::PaymentAddress::new(None, None, None, None),
            payment_id: common_utils::id_type::PaymentId::default()
                .get_string_repr()
                .to_owned(),
            #[cfg(feature = "payouts")]
            payout_method_data: None,
            #[cfg(feature = "payouts")]
            quote_id: None,
            payment_method_balance: None,
            connector_http_status_code: None,
            external_latency: None,
            apple_pay_flow: None,
            frm_metadata: None,
            refund_id: None,
            dispute_id: None,
            connector_response: None,
            integrity_check: Ok(()),
            additional_merchant_data: None,
            header_payload: None,
            connector_mandate_request_reference_id: None,
            authentication_id: None,
            psd2_sca_exemption_type: None,
            raw_connector_response: None,
            is_payment_id_from_merchant: None,
            l2_l3_data: None,
            minor_amount_capturable: None,
        }
    }
}

#[async_trait::async_trait]
pub trait VerifyConnector {
    async fn verify(
        state: &SessionState,
        connector_data: VerifyConnectorData,
    ) -> errors::RouterResponse<()> {
        let authorize_data = connector_data.get_payment_authorize_data();
        let access_token = Self::get_access_token(state, connector_data.clone()).await?;
        let router_data = connector_data.get_router_data(state, authorize_data, access_token);

        let request = connector_data
            .connector
            .get_connector_integration()
            .build_request(&router_data, &state.conf.connectors)
            .change_context(errors::ApiErrorResponse::InvalidRequestData {
                message: "Payment request cannot be built".to_string(),
            })?
            .ok_or(errors::ApiErrorResponse::InternalServerError)?;

        let response =
            services::call_connector_api(&state.to_owned(), request, "verify_connector_request")
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)?;

        match response {
            Ok(_) => Ok(services::ApplicationResponse::StatusOk),
            Err(error_response) => {
                Self::handle_payment_error_response::<
                    api::Authorize,
                    types::PaymentFlowData,
                    types::PaymentsAuthorizeData,
                    types::PaymentsResponseData,
                >(
                    connector_data.connector.get_connector_integration(),
                    error_response,
                )
                .await
            }
        }
    }

    async fn get_access_token(
        _state: &SessionState,
        _connector_data: VerifyConnectorData,
    ) -> errors::CustomResult<Option<types::AccessToken>, errors::ApiErrorResponse> {
        // AccessToken is None for the connectors without the AccessToken Flow.
        // If a connector has that, then it should override this implementation.
        Ok(None)
    }

    async fn handle_payment_error_response<F, ResourceCommonData, Req, Resp>(
        // connector: &(dyn api::Connector + Sync),
        connector: BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>,
        error_response: types::Response,
    ) -> errors::RouterResponse<()> {
        let error = connector
            .get_error_response(error_response, None)
            .change_context(errors::ApiErrorResponse::InternalServerError)?;
        Err(errors::ApiErrorResponse::InvalidRequestData {
            message: error.reason.unwrap_or(error.message),
        }
        .into())
    }

    async fn handle_access_token_error_response<F, ResourceCommonData, Req, Resp>(
        connector: BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>,
        error_response: types::Response,
    ) -> errors::RouterResult<Option<types::AccessToken>> {
        let error = connector
            .get_error_response(error_response, None)
            .change_context(errors::ApiErrorResponse::InternalServerError)?;
        Err(errors::ApiErrorResponse::InvalidRequestData {
            message: error.reason.unwrap_or(error.message),
        }
        .into())
    }
}


// Struct: AuthorizedotnetErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/authorizedotnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AuthorizedotnetErrorResponse


// Struct: PaymentType
// File: crates/hyperswitch_connectors/src/connectors/silverflow/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentType


// Implementation: impl api::PaymentSession for for Trustpay
// File: crates/hyperswitch_connectors/src/connectors/trustpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSession for for Trustpay


// Struct: NoonRefundResponseTransactions
// File: crates/hyperswitch_connectors/src/connectors/noon/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NoonRefundResponseTransactions


// Function: insert_resource
// File: crates/storage_impl/src/kv_router_store.rs
// Module: storage_impl

pub fn insert_resource<D, R, M>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        storage_scheme: MerchantStorageScheme,
        create_resource_fut: R,
        resource_new: M,
        InsertResourceParams {
            insertable,
            reverse_lookups,
            key,
            identifier,
            resource_type,
        }: InsertResourceParams<'_>,
    ) -> error_stack::Result<D, errors::StorageError>
    where
        D: Debug + Sync + Conversion,
        M: StorageModel<D>,
        R: futures::Future<Output = error_stack::Result<M, DatabaseError>> + Send,


// Implementation: impl User
// File: crates/diesel_models/src/query/user.rs
// Module: diesel_models
// Methods: 6 total (0 public)

impl User


// Implementation: impl ReverseLookupInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 2 total (0 public)

impl ReverseLookupInterface for for KafkaStore


// Struct: UnifiedAuthenticationServicePostAuthenticateResponse
// File: crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct UnifiedAuthenticationServicePostAuthenticateResponse


// Struct: PaymentInput
// File: crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentInput


// Struct: InvoiceHandler
// File: crates/router/src/core/subscription.rs
// Module: router
// Implementations: 1

pub struct InvoiceHandler


// Implementation: impl std::hash::Hash for for Maskable
// File: crates/masking/src/maskable.rs
// Module: masking
// Methods: 1 total (0 public)

impl std::hash::Hash for for Maskable


// Struct: RecipientCreateResponse
// File: crates/pm_auth/src/types.rs
// Module: pm_auth
// Implementations: 0

pub struct RecipientCreateResponse


// Struct: CloneConnectorDestination
// File: crates/api_models/src/user.rs
// Module: api_models
// Implementations: 0

pub struct CloneConnectorDestination


// Struct: Shipping
// File: crates/router/src/compatibility/stripe/payment_intents/types.rs
// Module: router
// Implementations: 0

pub struct Shipping