use super::EsdtTokenPayment;
use crate::{
    api::ManagedTypeApi,
    codec::{
        self,
        derive::{NestedDecode, NestedEncode, TopDecode, TopEncode},
    },
    types::{BigUint, ManagedVec},
};

use crate as multiversx_sc; // needed by the TypeAbi generated code
use crate::derive::type_abi;

/// Encodes any type of payment, which either:
/// - EGLD (can be zero in case of no payment whatsoever);
/// - Multi-ESDT (one or more ESDT transfers).
#[deprecated(
    note = "It comes from a time when only 1 EGLD payment, or ESDT multi-transfer was possible. This is no longer the case. Switch to `Payment` instead.",
    since = "0.64.0"
)]
#[type_abi]
#[derive(TopDecode, TopEncode, NestedDecode, NestedEncode, Clone, PartialEq, Eq, Debug)]
pub enum EgldOrMultiEsdtPayment<M: ManagedTypeApi> {
    Egld(BigUint<M>),
    MultiEsdt(ManagedVec<M, EsdtTokenPayment<M>>),
}

impl<M: ManagedTypeApi> EgldOrMultiEsdtPayment<M> {
    pub fn is_empty(&self) -> bool {
        match self {
            EgldOrMultiEsdtPayment::Egld(egld_value) => egld_value == &0u32,
            EgldOrMultiEsdtPayment::MultiEsdt(esdt_payments) => esdt_payments.is_empty(),
        }
    }
}

/// The version of `EgldOrMultiEsdtPayment` that contains references instead of owned fields.
pub enum EgldOrMultiEsdtPaymentRefs<'a, M: ManagedTypeApi> {
    Egld(&'a BigUint<M>),
    MultiEsdt(&'a ManagedVec<M, EsdtTokenPayment<M>>),
}

impl<M: ManagedTypeApi> EgldOrMultiEsdtPayment<M> {
    pub fn as_refs(&self) -> EgldOrMultiEsdtPaymentRefs<'_, M> {
        match self {
            EgldOrMultiEsdtPayment::Egld(egld_value) => {
                EgldOrMultiEsdtPaymentRefs::Egld(egld_value)
            }
            EgldOrMultiEsdtPayment::MultiEsdt(esdt_payments) => {
                EgldOrMultiEsdtPaymentRefs::MultiEsdt(esdt_payments)
            }
        }
    }
}

impl<M: ManagedTypeApi> EgldOrMultiEsdtPaymentRefs<'_, M> {
    pub fn to_owned_payment(&self) -> EgldOrMultiEsdtPayment<M> {
        match self {
            EgldOrMultiEsdtPaymentRefs::Egld(egld_value) => {
                EgldOrMultiEsdtPayment::Egld((*egld_value).clone())
            }
            EgldOrMultiEsdtPaymentRefs::MultiEsdt(esdt_payments) => {
                EgldOrMultiEsdtPayment::MultiEsdt((*esdt_payments).clone())
            }
        }
    }

    pub fn is_empty(&self) -> bool {
        match self {
            EgldOrMultiEsdtPaymentRefs::Egld(egld_value) => *egld_value == &0u32,
            EgldOrMultiEsdtPaymentRefs::MultiEsdt(esdt_payments) => esdt_payments.is_empty(),
        }
    }
}
