use cards::CardNumber;
use common_enums::{enums, Currency};
use common_utils::{pii::Email, types::StringMajorUnit};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{ConnectorAuthType, ErrorResponse},
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::ResponseId,
    router_response_types::{MandateReference, PaymentsResponseData, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{consts::NO_ERROR_CODE, errors};
use hyperswitch_masking::{ExposeInterface, Secret};
use serde::{Deserialize, Deserializer, Serialize};

use crate::{
    types::{
        PaymentsCaptureResponseRouterData, PaymentsResponseRouterData,
        PaymentsSyncResponseRouterData, RefundsResponseRouterData,
    },
    utils::{CardData, PaymentsAuthorizeRequestData, RefundsRequestData, RouterData as _},
};

pub struct ElavonRouterData<T> {
    pub amount: StringMajorUnit,
    pub router_data: T,
}

impl<T> From<(StringMajorUnit, T)> for ElavonRouterData<T> {
    fn from((amount, item): (StringMajorUnit, T)) -> Self {
        Self {
            amount,
            router_data: item,
        }
    }
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum TransactionType {
    CcSale,
    CcAuthOnly,
    CcComplete,
    CcReturn,
    TxnQuery,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "UPPERCASE")]
pub enum SyncTransactionType {
    Sale,
    AuthOnly,
    Return,
}

#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum ElavonPaymentsRequest {
    Card(CardPaymentRequest),
    MandatePayment(MandatePaymentRequest),
}
#[derive(Debug, Serialize)]
pub struct CardPaymentRequest {
    pub ssl_transaction_type: TransactionType,
    pub ssl_account_id: Secret<String>,
    pub ssl_user_id: Secret<String>,
    pub ssl_pin: Secret<String>,
    pub ssl_amount: StringMajorUnit,
    pub ssl_card_number: CardNumber,
    pub ssl_exp_date: Secret<String>,
    pub ssl_cvv2cvc2: Secret<String>,
    pub ssl_email: Email,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ssl_add_token: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ssl_get_token: Option<String>,
    pub ssl_transaction_currency: Currency,
}
#[derive(Debug, Serialize)]
pub struct MandatePaymentRequest {
    pub ssl_transaction_type: TransactionType,
    pub ssl_account_id: Secret<String>,
    pub ssl_user_id: Secret<String>,
    pub ssl_pin: Secret<String>,
    pub ssl_amount: StringMajorUnit,
    pub ssl_email: Email,
    pub ssl_token: Secret<String>,
}

impl TryFrom<&ElavonRouterData<&PaymentsAuthorizeRouterData>> for ElavonPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &ElavonRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let auth = ElavonAuthType::try_from(&item.router_data.connector_auth_type)?;

        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(req_card) => {
                if item.router_data.is_three_ds() {
                    Err(errors::ConnectorError::NotSupported {
                        message: "Card 3DS".to_string(),
                        connector: "Elavon",
                    })?
                };
                Ok(Self::Card(CardPaymentRequest {
                    ssl_transaction_type: match item.router_data.request.is_auto_capture()? {
                        true => TransactionType::CcSale,
                        false => TransactionType::CcAuthOnly,
                    },
                    ssl_account_id: auth.account_id.clone(),
                    ssl_user_id: auth.user_id.clone(),
                    ssl_pin: auth.pin.clone(),
                    ssl_amount: item.amount.clone(),
                    ssl_card_number: req_card.card_number.clone(),
                    ssl_exp_date: req_card.get_expiry_date_as_mmyy()?,
                    ssl_cvv2cvc2: req_card.card_cvc,
                    ssl_email: item.router_data.get_billing_email()?,
                    ssl_add_token: match item.router_data.request.is_mandate_payment() {
                        true => Some("Y".to_string()),
                        false => None,
                    },
                    ssl_get_token: match item.router_data.request.is_mandate_payment() {
                        true => Some("Y".to_string()),
                        false => None,
                    },
                    ssl_transaction_currency: item.router_data.request.currency,
                }))
            }
            PaymentMethodData::MandatePayment => Ok(Self::MandatePayment(MandatePaymentRequest {
                ssl_transaction_type: match item.router_data.request.is_auto_capture()? {
                    true => TransactionType::CcSale,
                    false => TransactionType::CcAuthOnly,
                },
                ssl_account_id: auth.account_id.clone(),
                ssl_user_id: auth.user_id.clone(),
                ssl_pin: auth.pin.clone(),
                ssl_amount: item.amount.clone(),
                ssl_email: item.router_data.get_billing_email()?,
                ssl_token: Secret::new(item.router_data.request.get_connector_mandate_id()?),
            })),
            _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
        }
    }
}

pub struct ElavonAuthType {
    pub(super) account_id: Secret<String>,
    pub(super) user_id: Secret<String>,
    pub(super) pin: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for ElavonAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::SignatureKey {
                api_key,
                key1,
                api_secret,
            } => Ok(Self {
                account_id: api_key.to_owned(),
                user_id: key1.to_owned(),
                pin: api_secret.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
enum SslResult {
    #[serde(rename = "0")]
    ImportedBatchFile,
    #[serde(other)]
    DeclineOrUnauthorized,
}

#[derive(Debug, Clone, Serialize)]
pub struct ElavonPaymentsResponse {
    pub result: ElavonResult,
}
#[derive(Debug, Clone, Serialize)]
pub enum ElavonResult {
    Success(PaymentResponse),
    Error(ElavonErrorResponse),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ElavonErrorResponse {
    error_code: Option<String>,
    error_message: String,
    error_name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaymentResponse {
    ssl_result: SslResult,
    ssl_txn_id: String,
    ssl_result_message: String,
    ssl_token: Option<Secret<String>>,
}
impl<'de> Deserialize<'de> for ElavonPaymentsResponse {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(Deserialize, Debug)]
        #[serde(rename = "txn")]
        struct XmlResponse {
            // Error fields
            #[serde(rename = "errorCode", default)]
            error_code: Option<String>,
            #[serde(rename = "errorMessage", default)]
            error_message: Option<String>,
            #[serde(rename = "errorName", default)]
            error_name: Option<String>,

            // Success fields
            #[serde(rename = "ssl_result", default)]
            ssl_result: Option<SslResult>,
            #[serde(rename = "ssl_txn_id", default)]
            ssl_txn_id: Option<String>,
            #[serde(rename = "ssl_result_message", default)]
            ssl_result_message: Option<String>,
            #[serde(rename = "ssl_token", default)]
            ssl_token: Option<Secret<String>>,
        }

        let xml_res = XmlResponse::deserialize(deserializer)?;

        let result = match (xml_res.error_message.clone(), xml_res.error_name.clone()) {
            (Some(error_message), Some(error_name)) => ElavonResult::Error(ElavonErrorResponse {
                error_code: xml_res.error_code.clone(),
                error_message,
                error_name,
            }),
            _ => {
                if let (Some(ssl_result), Some(ssl_txn_id), Some(ssl_result_message)) = (
                    xml_res.ssl_result.clone(),
                    xml_res.ssl_txn_id.clone(),
                    xml_res.ssl_result_message.clone(),
                ) {
                    ElavonResult::Success(PaymentResponse {
                        ssl_result,
                        ssl_txn_id,
                        ssl_result_message,
                        ssl_token: xml_res.ssl_token.clone(),
                    })
                } else {
                    return Err(serde::de::Error::custom(
                        "Invalid Response XML structure - neither error nor success",
                    ));
                }
            }
        };

        Ok(Self { result })
    }
}
impl TryFrom<PaymentsResponseRouterData<ElavonPaymentsResponse>> for PaymentsAuthorizeRouterData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsResponseRouterData<ElavonPaymentsResponse>,
    ) -> Result<Self, Self::Error> {
        let status =
            get_payment_status(&item.response.result, item.data.request.is_auto_capture()?);
        let response = match &item.response.result {
            ElavonResult::Error(error) => Err(ErrorResponse {
                code: error
                    .error_code
                    .clone()
                    .unwrap_or(NO_ERROR_CODE.to_string()),
                message: error.error_message.clone(),
                reason: Some(error.error_message.clone()),
                attempt_status: None,
                connector_transaction_id: None,
                connector_response_reference_id: None,
                status_code: item.http_code,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }),
            ElavonResult::Success(response) => {
                if status == enums::AttemptStatus::Failure {
                    Err(ErrorResponse {
                        code: response.ssl_result_message.clone(),
                        message: response.ssl_result_message.clone(),
                        reason: Some(response.ssl_result_message.clone()),
                        attempt_status: None,
                        connector_transaction_id: Some(response.ssl_txn_id.clone()),
                        connector_response_reference_id: None,
                        status_code: item.http_code,
                        network_advice_code: None,
                        network_decline_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    })
                } else {
                    Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::ConnectorTransactionId(
                            response.ssl_txn_id.clone(),
                        ),
                        redirection_data: Box::new(None),
                        mandate_reference: Box::new(Some(MandateReference {
                            connector_mandate_id: response
                                .ssl_token
                                .as_ref()
                                .map(|secret| secret.clone().expose()),
                            payment_method_id: None,
                            mandate_metadata: None,
                            connector_mandate_request_reference_id: None,
                        })),
                        connector_metadata: None,
                        network_txn_id: None,
                        network_txn_link_id: None,
                        connector_response_reference_id: Some(response.ssl_txn_id.clone()),
                        incremental_authorization_allowed: None,
                        authentication_data: None,
                        charges: None,
                    })
                }
            }
        };
        Ok(Self {
            status,
            response,
            ..item.data
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub enum TransactionSyncStatus {
    PEN, // Pended
    OPN, // Unpended / release / open
    REV, // Review
    STL, // Settled
    PST, // Failed due to post-auth rule
    FPR, // Failed due to fraud prevention rules
    PRE, // Failed due to pre-auth rule
}

#[derive(Debug, Serialize)]
#[serde(rename = "txn")]
pub struct PaymentsCaptureRequest {
    pub ssl_transaction_type: TransactionType,
    pub ssl_account_id: Secret<String>,
    pub ssl_user_id: Secret<String>,
    pub ssl_pin: Secret<String>,
    pub ssl_amount: StringMajorUnit,
    pub ssl_txn_id: String,
}
#[derive(Debug, Serialize)]
#[serde(rename = "txn")]
pub struct PaymentsVoidRequest {
    pub ssl_transaction_type: TransactionType,
    pub ssl_account_id: Secret<String>,
    pub ssl_user_id: Secret<String>,
    pub ssl_pin: Secret<String>,
    pub ssl_txn_id: String,
}

#[derive(Debug, Serialize)]
#[serde(rename = "txn")]
pub struct ElavonRefundRequest {
    pub ssl_transaction_type: TransactionType,
    pub ssl_account_id: Secret<String>,
    pub ssl_user_id: Secret<String>,
    pub ssl_pin: Secret<String>,
    pub ssl_amount: StringMajorUnit,
    pub ssl_txn_id: String,
}

#[derive(Debug, Serialize)]
#[serde(rename = "txn")]
pub struct SyncRequest {
    pub ssl_transaction_type: TransactionType,
    pub ssl_account_id: Secret<String>,
    pub ssl_user_id: Secret<String>,
    pub ssl_pin: Secret<String>,
    pub ssl_txn_id: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename = "txn")]
pub struct ElavonSyncResponse {
    pub ssl_trans_status: TransactionSyncStatus,
    pub ssl_transaction_type: SyncTransactionType,
    pub ssl_txn_id: String,
}
impl TryFrom<&RefundSyncRouterData> for SyncRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &RefundSyncRouterData) -> Result<Self, Self::Error> {
        let auth = ElavonAuthType::try_from(&item.connector_auth_type)?;
        Ok(Self {
            ssl_txn_id: item.request.get_connector_refund_id()?,
            ssl_transaction_type: TransactionType::TxnQuery,
            ssl_account_id: auth.account_id.clone(),
            ssl_user_id: auth.user_id.clone(),
            ssl_pin: auth.pin.clone(),
        })
    }
}
impl TryFrom<&PaymentsSyncRouterData> for SyncRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentsSyncRouterData) -> Result<Self, Self::Error> {
        let auth = ElavonAuthType::try_from(&item.connector_auth_type)?;
        Ok(Self {
            ssl_txn_id: item
                .request
                .connector_transaction_id
                .get_connector_transaction_id()
                .change_context(errors::ConnectorError::MissingConnectorTransactionID)?,
            ssl_transaction_type: TransactionType::TxnQuery,
            ssl_account_id: auth.account_id.clone(),
            ssl_user_id: auth.user_id.clone(),
            ssl_pin: auth.pin.clone(),
        })
    }
}
impl<F> TryFrom<&ElavonRouterData<&RefundsRouterData<F>>> for ElavonRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &ElavonRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        let auth = ElavonAuthType::try_from(&item.router_data.connector_auth_type)?;
        Ok(Self {
            ssl_txn_id: item.router_data.request.connector_transaction_id.clone(),
            ssl_amount: item.amount.clone(),
            ssl_transaction_type: TransactionType::CcReturn,
            ssl_account_id: auth.account_id.clone(),
            ssl_user_id: auth.user_id.clone(),
            ssl_pin: auth.pin.clone(),
        })
    }
}

impl TryFrom<&ElavonRouterData<&PaymentsCaptureRouterData>> for PaymentsCaptureRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &ElavonRouterData<&PaymentsCaptureRouterData>) -> Result<Self, Self::Error> {
        let auth = ElavonAuthType::try_from(&item.router_data.connector_auth_type)?;
        Ok(Self {
            ssl_txn_id: item.router_data.request.connector_transaction_id.clone(),
            ssl_amount: item.amount.clone(),
            ssl_transaction_type: TransactionType::CcComplete,
            ssl_account_id: auth.account_id.clone(),
            ssl_user_id: auth.user_id.clone(),
            ssl_pin: auth.pin.clone(),
        })
    }
}

impl TryFrom<PaymentsSyncResponseRouterData<ElavonSyncResponse>> for PaymentsSyncRouterData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsSyncResponseRouterData<ElavonSyncResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: get_sync_status(item.data.status, &item.response),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.ssl_txn_id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                network_txn_link_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                authentication_data: None,
                charges: None,
            }),
            ..item.data
        })
    }
}
impl TryFrom<RefundsResponseRouterData<RSync, ElavonSyncResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, ElavonSyncResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.ssl_txn_id.clone(),
                refund_status: get_refund_status(item.data.request.refund_status, &item.response),
            }),
            ..item.data
        })
    }
}

impl TryFrom<PaymentsCaptureResponseRouterData<ElavonPaymentsResponse>>
    for PaymentsCaptureRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsCaptureResponseRouterData<ElavonPaymentsResponse>,
    ) -> Result<Self, Self::Error> {
        let status = map_payment_status(&item.response.result, enums::AttemptStatus::Charged);
        let response = match &item.response.result {
            ElavonResult::Error(error) => Err(ErrorResponse {
                code: error
                    .error_code
                    .clone()
                    .unwrap_or(NO_ERROR_CODE.to_string()),
                message: error.error_message.clone(),
                reason: Some(error.error_message.clone()),
                attempt_status: None,
                connector_transaction_id: None,
                connector_response_reference_id: None,
                status_code: item.http_code,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }),
            ElavonResult::Success(response) => {
                if status == enums::AttemptStatus::Failure {
                    Err(ErrorResponse {
                        code: response.ssl_result_message.clone(),
                        message: response.ssl_result_message.clone(),
                        reason: Some(response.ssl_result_message.clone()),
                        attempt_status: None,
                        connector_transaction_id: None,
                        connector_response_reference_id: None,
                        status_code: item.http_code,
                        network_advice_code: None,
                        network_decline_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    })
                } else {
                    Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::ConnectorTransactionId(
                            response.ssl_txn_id.clone(),
                        ),
                        redirection_data: Box::new(None),
                        mandate_reference: Box::new(None),
                        connector_metadata: None,
                        network_txn_id: None,
                        network_txn_link_id: None,
                        connector_response_reference_id: Some(response.ssl_txn_id.clone()),
                        incremental_authorization_allowed: None,
                        authentication_data: None,
                        charges: None,
                    })
                }
            }
        };
        Ok(Self {
            status,
            response,
            ..item.data
        })
    }
}
impl TryFrom<RefundsResponseRouterData<Execute, ElavonPaymentsResponse>>
    for RefundsRouterData<Execute>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, ElavonPaymentsResponse>,
    ) -> Result<Self, Self::Error> {
        let status = enums::RefundStatus::from(&item.response.result);
        let response = match &item.response.result {
            ElavonResult::Error(error) => Err(ErrorResponse {
                code: error
                    .error_code
                    .clone()
                    .unwrap_or(NO_ERROR_CODE.to_string()),
                message: error.error_message.clone(),
                reason: Some(error.error_message.clone()),
                attempt_status: None,
                connector_transaction_id: None,
                connector_response_reference_id: None,
                status_code: item.http_code,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }),
            ElavonResult::Success(response) => {
                if status == enums::RefundStatus::Failure {
                    Err(ErrorResponse {
                        code: response.ssl_result_message.clone(),
                        message: response.ssl_result_message.clone(),
                        reason: Some(response.ssl_result_message.clone()),
                        attempt_status: None,
                        connector_transaction_id: None,
                        connector_response_reference_id: None,
                        status_code: item.http_code,
                        network_advice_code: None,
                        network_decline_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    })
                } else {
                    Ok(RefundsResponseData {
                        connector_refund_id: response.ssl_txn_id.clone(),
                        refund_status: enums::RefundStatus::from(&item.response.result),
                    })
                }
            }
        };
        Ok(Self {
            response,
            ..item.data
        })
    }
}

trait ElavonResponseValidator {
    fn is_successful(&self) -> bool;
}
impl ElavonResponseValidator for ElavonResult {
    fn is_successful(&self) -> bool {
        matches!(self, Self::Success(response) if response.ssl_result == SslResult::ImportedBatchFile)
    }
}

fn map_payment_status(
    item: &ElavonResult,
    success_status: enums::AttemptStatus,
) -> enums::AttemptStatus {
    if item.is_successful() {
        success_status
    } else {
        enums::AttemptStatus::Failure
    }
}

impl From<&ElavonResult> for enums::RefundStatus {
    fn from(item: &ElavonResult) -> Self {
        if item.is_successful() {
            Self::Success
        } else {
            Self::Failure
        }
    }
}
fn get_refund_status(
    prev_status: enums::RefundStatus,
    item: &ElavonSyncResponse,
) -> enums::RefundStatus {
    match item.ssl_trans_status {
        TransactionSyncStatus::REV | TransactionSyncStatus::OPN | TransactionSyncStatus::PEN => {
            prev_status
        }
        TransactionSyncStatus::STL => enums::RefundStatus::Success,
        TransactionSyncStatus::PST | TransactionSyncStatus::FPR | TransactionSyncStatus::PRE => {
            enums::RefundStatus::Failure
        }
    }
}
impl From<&ElavonSyncResponse> for enums::AttemptStatus {
    fn from(item: &ElavonSyncResponse) -> Self {
        match item.ssl_trans_status {
            TransactionSyncStatus::REV
            | TransactionSyncStatus::OPN
            | TransactionSyncStatus::PEN => Self::Pending,
            TransactionSyncStatus::STL => match item.ssl_transaction_type {
                SyncTransactionType::Sale => Self::Charged,
                SyncTransactionType::AuthOnly => Self::Authorized,
                SyncTransactionType::Return => Self::Pending,
            },
            TransactionSyncStatus::PST
            | TransactionSyncStatus::FPR
            | TransactionSyncStatus::PRE => Self::Failure,
        }
    }
}
fn get_sync_status(
    prev_status: enums::AttemptStatus,
    item: &ElavonSyncResponse,
) -> enums::AttemptStatus {
    match item.ssl_trans_status {
        TransactionSyncStatus::REV | TransactionSyncStatus::OPN | TransactionSyncStatus::PEN => {
            prev_status
        }
        TransactionSyncStatus::STL => match item.ssl_transaction_type {
            SyncTransactionType::Sale => enums::AttemptStatus::Charged,
            SyncTransactionType::AuthOnly => enums::AttemptStatus::Authorized,
            SyncTransactionType::Return => enums::AttemptStatus::Pending,
        },
        TransactionSyncStatus::PST | TransactionSyncStatus::FPR | TransactionSyncStatus::PRE => {
            enums::AttemptStatus::Failure
        }
    }
}

fn get_payment_status(item: &ElavonResult, is_auto_capture: bool) -> enums::AttemptStatus {
    if item.is_successful() {
        if is_auto_capture {
            enums::AttemptStatus::Charged
        } else {
            enums::AttemptStatus::Authorized
        }
    } else {
        enums::AttemptStatus::Failure
    }
}
