package com.braintree.configuration.service;

import com.braintree.daos.BrainTreeBaseStoreDao;
import com.braintree.enums.BraintreePageType;
import com.braintree.enums.BraintreeThreeDSecureFlow;
import com.braintree.exceptions.BrainTreePluginConfigurationNotFound;
import com.braintreegateway.Environment;
import com.braintreegateway.util.BraintreeCrypto;
import de.hybris.platform.basecommerce.model.site.BaseSiteModel;
import de.hybris.platform.core.model.BraintreePluginConfigurationModel;
import de.hybris.platform.core.model.c2l.CurrencyModel;
import de.hybris.platform.servicelayer.config.ConfigurationService;
import de.hybris.platform.servicelayer.i18n.CommonI18NService;
import de.hybris.platform.servicelayer.user.UserService;
import de.hybris.platform.site.BaseSiteService;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import de.hybris.platform.store.BaseStoreModel;
import de.hybris.platform.store.services.BaseStoreService;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.util.Strings;

import static com.braintree.constants.BraintreeConstants.PAYPAL_CONNECT_SCOPES;
import static com.braintree.constants.BraintreeConstants.PAYPAL_CONNECT_SCRIPT;
import static com.braintree.constants.BraintreeConstants.PAYPAL_CONNECT_RESPONSE_TYPE;
import static com.braintree.constants.BraintreeConstants.CLIENT_ID;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.B2C_ENDPOINT_URL_PROPERTY;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_CHANNEL_NAME;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_ENVIRONMENT;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_IMAGES_PREFIX;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_KEY;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_LOCALE;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_SEARCH_LIMIT;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_SRC_IMG_URL;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_SRC_SDK_URL;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_USER_ACTION;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.HYBRIS_BUILD_API_VERSION;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.MULTICAPTURE_ENABLED;
import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_DISPLAY_NAME;
import static com.braintree.constants.BraintreeConstants.SECRET_KEY;
import static com.braintree.constants.BraintreeConstants.PAYPAL_API_URL;
import static com.braintree.constants.BraintreeConstants.ENVIRONMENT_SANDBOX;
import static com.braintree.constants.BraintreeConstants.ENVIRONMENT_PRODUCTION;
import static com.braintree.constants.BraintreeConstants.COMMA_SEPARATOR;
import static com.braintree.constants.BraintreeConstants.BRAINTREE_ACCEPTED_PAYMENT_METHODS_DELIMETER;
import static com.braintree.constants.BraintreeConstants.BRAINTREE_DISABLE_FUNDING_ON_MY_ACCOUNT;
import static com.braintree.constants.BraintreeConstants.CARD_FUNDING_SOURCE;
import static java.util.Optional.ofNullable;

public class BrainTreeConfigService {

    private static final Logger LOG = Logger.getLogger(BrainTreeConfigService.class);
    public static final String BRAIN_TREE_PLUGIN_CONFIGURATION_HAS_NOT_BEEN_FOUND_ERROR_MSG = "BrainTreePluginConfiguration has not been found";
    private final Map<String, Environment> ENV_TYPE_MAP = new HashMap<>();
    private BaseSiteService baseSiteService;
    private BaseStoreService baseStoreService;
    private CommonI18NService commonI18NService;
    private ConfigurationService configurationService;
    private UserService userService;
    private BrainTreeBaseStoreDao brainTreeBaseStoreDao;

    public BrainTreeConfigService() {
        ENV_TYPE_MAP.put(ENVIRONMENT_SANDBOX, Environment.SANDBOX);
        ENV_TYPE_MAP.put(ENVIRONMENT_PRODUCTION, Environment.PRODUCTION);
    }

    public BraintreeThreeDSecureFlow getThreeDSecureFlow() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().getBraintreeThreeDSecureFlow();
    }

    public boolean isAdvancedFraudTools() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().isAdvancedFraudTools();
    }

    public boolean isApplePayEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeApplePayConfiguration().isEnabled();
    }

    public boolean isApplePayOnExpressCheckoutEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeApplePayConfiguration().isExpressCheckout();
    }

    public boolean isChangePaymentMethodButtonEnabled() {
        return getBrainTreePluginConfiguration().getBraintreePayPalConfiguration().isChangePaymentMethodButton();
    }

    public String getPayPalDisableFunding() {
        return getBrainTreePluginConfiguration().getBraintreePayPalConfiguration().getDisableFunding();
    }

    public boolean isPayLaterEnabled() {
        return getBrainTreePluginConfiguration().getBraintreePayPalConfiguration().isPayLater();
    }

    public boolean isDropInEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().isDropIn();
    }

    public boolean isGooglePayEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeGooglePayConfiguration().isEnabled();
    }

    public boolean isGooglePayOnExpressCheckoutEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeGooglePayConfiguration().isExpressCheckout();
    }

    public boolean isHostedFieldEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeHostedFieldsConfiguration().isEnabled();
    }

    public boolean isLocalPaymentsEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeLocalPaymentsConfiguration().isEnabled();
    }

    public boolean isMultiCaptureEnabled() {
        return getConfiguration().getBoolean(MULTICAPTURE_ENABLED, true);
    }

    public boolean isOneOfPaymentMethodsEnabled() {
        return Stream.of(isPayPalEnabled(), isHostedFieldEnabled(), isVenmoEnabled(),
                        isLocalPaymentsEnabled(), isApplePayEnabled(), isGooglePayEnabled(), isSrcEnabled())
                .anyMatch(x -> x);
    }

    public boolean isPayLaterEnabledForNonUsCountries() {
        return getBrainTreePluginConfiguration().getBraintreePayPalConfiguration().isPayLaterForNonUsCountries();
    }

    public boolean isPayPalExpressEnabled() {
        return getBrainTreePluginConfiguration().getBraintreePayPalConfiguration().isExpressCheckout();
    }

    public boolean isPayPalEnabled() {
        return getBrainTreePluginConfiguration().getBraintreePayPalConfiguration().isPayPalEnabled();
    }

    public boolean is3dSecureConfiguration() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().getBraintreeThreeDSecureFlow()
                != BraintreeThreeDSecureFlow.DISABLED;
    }

    public boolean isSrcEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeSRCConfiguration().isEnabled();
    }

    public boolean isStoreInVault() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().isStoreInVault();
    }

    public boolean isStoreInVaultForCurrentUser() {
        if (userService.isAnonymousUser(userService.getCurrentUser())) {
            return Boolean.FALSE;
        }
        return isStoreInVault();
    }

    public boolean isStoreInVaultForCardVaulting(String braintreeCustomerId) {
        return !(StringUtils.isEmpty(braintreeCustomerId)) && isStoreInVault();
    }

    public boolean isSubmitForSettlement() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().isSubmitForSettlement();
    }

    public int getBrainTreeCreditCartExpireBetween(){
        return getBrainTreePluginConfiguration().getBraintreeHostedFieldsConfiguration().getExpireBetween();
    }

    public boolean isBrainTreeCreditExpireOnAddingValidation() {
        return getBrainTreePluginConfiguration().getBraintreeHostedFieldsConfiguration().isExpireOnAdding();
    }

    public boolean isVenmoEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeVenmoConfiguration().isEnabled();
    }

    public boolean isUsBankAccountEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeACHConfiguration().isEnabled();
    }

    public String getUsBankAccountMerchantName() {
        return getBrainTreePluginConfiguration().getBraintreeACHConfiguration().getMerchantName();
    }

    public boolean isVerifyCard() {
        return getBrainTreePluginConfiguration().getBraintreeHostedFieldsConfiguration().isVerifyCard();
    }

    public Map<String, String> getAcceptedPaymentMethodImages(final String paymentMethodsString) {
        final Map<String, String> acceptedPaymentMethodImages = new HashMap<>();
        final String acceptedPaymentMethods = getConfiguration().getString(paymentMethodsString);

        if (StringUtils.isNotBlank(acceptedPaymentMethods)) {
            final String paymentMethods = StringUtils.deleteWhitespace(acceptedPaymentMethods);
            final String[] paymentMethodList = StringUtils.split(paymentMethods, BRAINTREE_ACCEPTED_PAYMENT_METHODS_DELIMETER);

            for (final String paymentMethod : paymentMethodList) {
                final String imageLink = getConfiguration().getString(BRAINTREE_IMAGES_PREFIX + paymentMethod);
                if (StringUtils.isNotBlank(imageLink)) {
                    acceptedPaymentMethodImages.put(paymentMethod, imageLink);
                }
            }
        }
        return acceptedPaymentMethodImages;
    }

    public int getBackofficeSearchLimit() {
        return getConfiguration().getInt(BRAINTREE_SEARCH_LIMIT, 300);
    }

    public String getBillingAgreementDescription() {
        return getBrainTreePluginConfiguration().getBraintreePayPalConfiguration().getBillingAgreementText();
    }

    public String getBrainTreeChannel() {
        return BraintreeCrypto
            .decrypt(getConfiguration().getString(BRAINTREE_KEY), getConfiguration().getString(BRAINTREE_CHANNEL_NAME));
    }

    public String getBrainTreeLocale() {
        return getConfiguration().getString(BRAINTREE_LOCALE);
    }

    private Configuration getConfiguration() {
        return configurationService.getConfiguration();
    }

    public String getBrainTreeDisplayName() {
        return getConfiguration().getString(BRAINTREE_DISPLAY_NAME);
    }

    private String addDisabledFunding(String disableFunding, String add) {
        if (StringUtils.isEmpty(disableFunding)) {
            return add;
        }
        return disableFunding + COMMA_SEPARATOR + add;
    }

    public String getDisableFunding(final BraintreePageType pageType) {
        String disableFunding = getPayPalDisableFunding();
        if (BraintreePageType.ACCOUNT.equals(pageType)) {
            disableFunding = addDisabledFunding(disableFunding, BRAINTREE_DISABLE_FUNDING_ON_MY_ACCOUNT);
        }
        if (isChangePaymentMethodButtonEnabled()) {
            disableFunding = addDisabledFunding(disableFunding, CARD_FUNDING_SOURCE);
        }
        return disableFunding;
    }

    public String getCurrencyMerchantAccountId() {
        String currentCurrency = commonI18NService.getCurrentCurrency().getIsocode();
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().getMerchantAccountId().get(currentCurrency);
    }

    public String getEndpointURL() {
        return getConfiguration().getString(B2C_ENDPOINT_URL_PROPERTY);
    }

    public Environment getEnvironmentType() {
        if (ENV_TYPE_MAP.containsKey(getConfiguration().getString(BRAINTREE_ENVIRONMENT))) {
            return ENV_TYPE_MAP.get(getConfiguration().getString(BRAINTREE_ENVIRONMENT));
        }
        LOG.warn("Configuration environment property name is incorrect! Use environment: " + Environment.DEVELOPMENT);
        return Environment.DEVELOPMENT;
    }

    public String getEnvironmentTypeName() {
        return getEnvironmentType().getEnvironmentName();
    }

    public String getDescriptorBusinessName() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().getDescriptorBusinessName();
    }
    public String getDescriptorProductName() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().getDescriptorProductName();
    }

    public String getDescriptorPhoneNumber() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().getDescriptorPhoneNumber();
    }

    public String getDescriptorUrl() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().getDescriptorUrl();
    }

    public String getGooglePayMerchantId() {
        return getBrainTreePluginConfiguration().getBraintreeGooglePayConfiguration().getMerchantId();
    }

    public String getGooglePayCountryCode() {
        return getBrainTreePluginConfiguration().getBraintreeGooglePayConfiguration().getSellerCountryCode();
    }

    public Integer getHybrisBuildApiVersion() {
        String apiVersion = getConfiguration().getString(HYBRIS_BUILD_API_VERSION);
        if (StringUtils.isNotEmpty(apiVersion)) {
            String[] version = apiVersion.split("\\.");
            if (version.length > 0 && StringUtils.isNumeric(version[0])) {
                return Integer.valueOf(version[0]);
            }
        }
        return null;
    }

    public String getIntent() {
        return getBrainTreePluginConfiguration().getBraintreePayPalConfiguration().getIntent().getCode().toLowerCase();
    }

    public String getMerchantAccountIdForCurrentSiteAndCurrency() {
        return getMerchantAccountIdForCurrentSiteAndCurrencyIsoCode(
                ofNullable(commonI18NService.getCurrentCurrency())
                        .map(CurrencyModel::getIsocode)
                        .orElse(Strings.EMPTY));
    }

    public BraintreePluginConfigurationModel getBrainTreePluginConfiguration() {
        return ofNullable(baseStoreService.getCurrentBaseStore())
                .map(BaseStoreModel::getBraintreePluginConfiguration)
                .orElseThrow(() -> new BrainTreePluginConfigurationNotFound(BRAIN_TREE_PLUGIN_CONFIGURATION_HAS_NOT_BEEN_FOUND_ERROR_MSG));
    }

    public String getMerchantAccountIdForSiteAndCurrencyIsoCode(final String baseSiteUid, final String currencyIsoCode) {
        BraintreePluginConfigurationModel pluginConfiguration = ofNullable(baseSiteService.getBaseSiteForUID(baseSiteUid).getStores().get(0))
                .map(BaseStoreModel::getBraintreePluginConfiguration)
                .orElseThrow(() -> new BrainTreePluginConfigurationNotFound(BRAIN_TREE_PLUGIN_CONFIGURATION_HAS_NOT_BEEN_FOUND_ERROR_MSG));

        return pluginConfiguration
                .getBraintreeGeneralConfiguration().getMerchantAccountId().get(currencyIsoCode.toUpperCase(Locale.US));
    }

    public String getMerchantAccountIdForCurrentSiteAndCurrencyIsoCode(final String currency) {
        return getBrainTreePluginConfiguration()
                .getBraintreeGeneralConfiguration().getMerchantAccountId().get(currency.toUpperCase(Locale.US));
    }

    public String getUserAction() {
        return getConfiguration().getString(BRAINTREE_USER_ACTION);
    }

    public String getSrcSdkUrl() {
        return getConfiguration().getString(BRAINTREE_SRC_SDK_URL);
    }

    public String getSrcImgUrl() {
        return getConfiguration().getString(BRAINTREE_SRC_IMG_URL);
    }

    public String getVenmoProfileId() {
        return getBrainTreePluginConfiguration().getBraintreeVenmoConfiguration().getProfileId();
    }

    public boolean isPayPalConnectAddPaymentMethodFlow() {
        return getBrainTreePluginConfiguration().getBraintreeConnectWithPayPalConfiguration().isAddPaymentMethodFlow();
    }

    public boolean isConnectWithPayPalEnabled() {
        return getBrainTreePluginConfiguration().getBraintreeConnectWithPayPalConfiguration().isEnable();
    }

    public boolean isEnableLoginViaPayPalToTheExistingUser() {
        return getBrainTreePluginConfiguration().getBraintreeConnectWithPayPalConfiguration().isLinkUserAccount();
    }

    public boolean isPayPalLippAdditionalSecurityEnable() {
        return getBrainTreePluginConfiguration().getBraintreeConnectWithPayPalConfiguration().isLippAdditionalSecurity();
    }

    public boolean isBraintreeVerifyFlow() {
        return getBrainTreePluginConfiguration().getBraintreeHostedFieldsConfiguration().isReverify();
    }

    public boolean isRestrictionPaymentMethodRemovalEnable() {
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().isRestrictionOfPaymentMethodRemoval();
    }

    public int getRestrictionPaymentMethodRemovalExpiration(){
        return getBrainTreePluginConfiguration().getBraintreeGeneralConfiguration().getRestrictionOfPaymentMethodRemovalExpiration();
    }

    public Optional<BaseSiteModel> getBaseSiteForPayPalConfigurationId(String payPalConfigurationId) {
        List<BaseStoreModel> baseStoreOptional = brainTreeBaseStoreDao
                .findBaseStoresByPayPalConfiguration(payPalConfigurationId);
        return baseStoreOptional.stream().flatMap(baseStoreModel -> baseStoreModel.getCmsSites().stream()).findFirst();
    }

    public Optional<BaseSiteModel> getBaseSiteForGeneralConfigurationId(String generalConfigurationId) {
        List<BaseStoreModel> baseStoreOptional = brainTreeBaseStoreDao
                .findBaseStoresByGeneralConfiguration(generalConfigurationId);
        return baseStoreOptional.stream().flatMap(baseStoreModel -> baseStoreModel.getCmsSites().stream()).findFirst();
    }

    public List<BaseStoreModel> getBaseStoresByPluginConfiguration(BraintreePluginConfigurationModel pluginConfiguration) {
        return brainTreeBaseStoreDao.findBaseStoresByPluginConfiguration(pluginConfiguration);
    }

    public String getPayPalConnectScript() {
        return configurationService.getConfiguration().getString(PAYPAL_CONNECT_SCRIPT);
    }

    public String getPayPalConnectScopes() {
        return configurationService.getConfiguration().getString(PAYPAL_CONNECT_SCOPES);
    }

    public String getPayPalConnectResponseType() {
        return configurationService.getConfiguration().getString(PAYPAL_CONNECT_RESPONSE_TYPE);
    }

    public String getClientID() {
        return configurationService.getConfiguration().getString(CLIENT_ID);
    }

    public String getSecretKey() {
        return configurationService.getConfiguration().getString(SECRET_KEY);
    }

    public String getPayPalApiUrl() {
        return configurationService.getConfiguration().getString(PAYPAL_API_URL);
    }

    public void setBaseStoreService(BaseStoreService baseStoreService) {
        this.baseStoreService = baseStoreService;
    }

    public void setBaseSiteService(final BaseSiteService baseSiteService) {
        this.baseSiteService = baseSiteService;
    }

    public void setCommonI18NService(final CommonI18NService commonI18NService) {
        this.commonI18NService = commonI18NService;
    }

    public void setConfigurationService(final ConfigurationService configurationService) {
        this.configurationService = configurationService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void setBrainTreeBaseStoreDao(BrainTreeBaseStoreDao brainTreeBaseStoreDao) {
        this.brainTreeBaseStoreDao = brainTreeBaseStoreDao;
    }

}
