package com.braintree.facade.impl;

import com.braintree.configuration.service.BrainTreeConfigService;
import com.braintree.customer.service.BrainTreeCustomerAccountService;
import com.braintree.facade.BrainTreeConnectWithPayPalFacade;
import com.braintree.facade.BraintreeConnectWithPayPalNotificationFacade;
import com.braintree.hybris.data.BrainTreeConnectWithPayPalAddressData;
import com.braintree.hybris.data.BrainTreeConnectWithPayPalUserData;
import com.braintree.model.BrainTreePaymentInfoModel;
import com.braintree.service.BrainTreeConnectWithPayPalService;
import com.braintree.util.BrainTreeUtils;
import com.braintree.enums.BraintreePageType;
import de.hybris.platform.acceleratorservices.urlresolver.SiteBaseUrlResolutionService;
import de.hybris.platform.core.model.c2l.CountryModel;
import de.hybris.platform.core.model.c2l.RegionModel;
import de.hybris.platform.core.model.user.AddressModel;
import de.hybris.platform.core.model.user.CustomerModel;
import de.hybris.platform.servicelayer.i18n.CommonI18NService;
import de.hybris.platform.servicelayer.model.ModelService;
import de.hybris.platform.servicelayer.user.UserService;
import de.hybris.platform.site.BaseSiteService;
import org.apache.commons.lang.StringUtils;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;

public class DefaultBrainTreeConnectWithPayPalFacade implements BrainTreeConnectWithPayPalFacade {

    private static final String SPACE = " ";

    private BrainTreeConnectWithPayPalService brainTreeConnectWithPayPalService;
    private BrainTreeCustomerAccountService brainTreeCustomerAccountService;
    private UserService userService;
    private ModelService modelService;
    private CommonI18NService commonI18NService;
    private DefaultBrainTreeCheckoutFacade acceleratorCheckoutFacade;
    private BrainTreeConfigService brainTreeConfigService;
    private BraintreeConnectWithPayPalNotificationFacade braintreeConnectWithPayPalNotificationFacade;

    @Override
    public BrainTreeConnectWithPayPalUserData getUserDataByAccessToken(String accessToken) {
        return brainTreeConnectWithPayPalService.getUserDataByAccessToken(accessToken);
    }

    @Override
    public String getAccessToken() {
        return brainTreeConnectWithPayPalService.getAccessToken();
    }

    @Override
    public String exchangeAuthorizationCodeToAccessToken(String authorizationToken) {
        return brainTreeConnectWithPayPalService.exchangeAuthorizationCodeToAccessToken(authorizationToken);
    }

    @Override
    public void setAccessTokenForCustomer(String accessTokenGuid, String payerId) {
        brainTreeCustomerAccountService.setAccessTokenForCustomer(accessTokenGuid, payerId);
    }

    @Override
    public void setDefaultAccessToken(String payerId) {
        brainTreeCustomerAccountService.setDefaultAccessToken(payerId);
    }

    @Override
    public boolean isPayPalAddressPresent(String email, BrainTreeConnectWithPayPalAddressData addressData) {
        Collection<AddressModel> addresses = userService.getUserForUID(email).getAddresses();
        BiPredicate<String, String> compare = (s1, s2) -> {
            if (s1 == null && s2 == null) {
                return true;
            }
            return s1 != null && s1.equals(s2);
        };

        BiPredicate<AddressModel, BrainTreeConnectWithPayPalAddressData> compareRegion = (s1, s2) -> {
            if (s1.getRegion() == null && s2.getRegion() == null) {
                return true;
            }
            if (s1.getRegion() == null) {
                return false;
            }
            return s1.getRegion().getIsocodeShort().equals(s2.getRegion());
        };

        for (AddressModel addressModel : addresses) {
            if (compare.test(addressModel.getCountry().getIsocode(), addressData.getCountry())
                    && compareRegion.test(addressModel, addressData)
                    && compare.test(addressModel.getPostalcode(), addressData.getPostalCode())
                    && compare.test(addressModel.getLine1(), addressData.getStreetAddress())
                    && compare.test(addressModel.getTown(), addressData.getLocality())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isPayPalPaymentMethodPresent(String email) {
        final CustomerModel customerModel = (CustomerModel) userService.getUserForUID(email);
        final List<BrainTreePaymentInfoModel> paymentInfoList = brainTreeCustomerAccountService.getBrainTreePaymentInfos(customerModel, true);
        for (BrainTreePaymentInfoModel paymentInfoModel : paymentInfoList) {
            if (BrainTreeUtils.isPayPalPayment(paymentInfoModel.getPaymentProvider()) && paymentInfoModel.getPayer().equalsIgnoreCase(email)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isPayPalPaymentMethodPresentForConnectWithPayPal(String email) {
        final boolean isPayPalOnLimit = acceleratorCheckoutFacade.isPayPalLimitedDuringConnect(email);
        if (brainTreeConfigService.isPayPalEnabled() && brainTreeConfigService.isStoreInVault() && !isPayPalOnLimit) {
            return isPayPalPaymentMethodPresent(email);
        } else {
            return true;
        }
    }

    @Override
    public boolean shouldSavePayPalPaymentInfo() {
        return brainTreeConfigService.isPayPalEnabled() && brainTreeConfigService.isStoreInVault();
    }

    @Override
    public void addAddressForNewUser(BrainTreeConnectWithPayPalAddressData addressData, String email) {
        final AddressModel newAddress = modelService.create(AddressModel.class);
        final CountryModel countryModel = commonI18NService.getCountry(addressData.getCountry());
        final CustomerModel customer = (CustomerModel) userService.getUserForUID(email);

        if (StringUtils.isNotBlank(addressData.getRegion())) {
            final String regionIsoCode = String.format("%s-%s", countryModel.getIsocode(), addressData.getRegion());
            final RegionModel regionModel = commonI18NService.getRegion(countryModel, regionIsoCode);
            newAddress.setRegion(regionModel);
            modelService.save(regionModel);
        }

        List<String> fullName = Arrays.asList(customer.getName().split(SPACE));
        newAddress.setFirstname(fullName.stream().findFirst().orElse(StringUtils.EMPTY));
        newAddress.setLastname(fullName.stream().skip(1).collect(Collectors.joining(SPACE)));
        newAddress.setEmail(customer.getContactEmail());
        newAddress.setCountry(countryModel);
        newAddress.setTown(addressData.getLocality());
        newAddress.setLine1(addressData.getStreetAddress());
        newAddress.setPostalcode(addressData.getPostalCode());
        newAddress.setShippingAddress(true);

        customer.setDefaultShipmentAddress(newAddress);
        customer.setDefaultPaymentAddress(newAddress);
        brainTreeCustomerAccountService.saveAddressEntry(customer, newAddress);
    }

    @Override
    public boolean unlinkConnectWithPayPalAccount() {
        CustomerModel customerModel = (CustomerModel) userService.getCurrentUser();
        if (customerModel != null && StringUtils.isNotBlank(customerModel.getPayPalPayerId())) {
            customerModel.setPayPalPayerId(null);
            modelService.save(customerModel);
            braintreeConnectWithPayPalNotificationFacade.sendUnlinkCustomerEmailNotification(customerModel.getUid());
            return true;
        }
        return false;
    }

    public void setBrainTreeConnectWithPayPalService(
            BrainTreeConnectWithPayPalService brainTreeConnectWithPayPalService) {
        this.brainTreeConnectWithPayPalService = brainTreeConnectWithPayPalService;
    }

    public void setBrainTreeCustomerAccountService(
            BrainTreeCustomerAccountService brainTreeCustomerAccountService) {
        this.brainTreeCustomerAccountService = brainTreeCustomerAccountService;
    }

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

    public void setModelService(ModelService modelService) {
        this.modelService = modelService;
    }

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

    public void setBrainTreeConfigService(BrainTreeConfigService brainTreeConfigService) {
        this.brainTreeConfigService = brainTreeConfigService;
    }

    public void setAcceleratorCheckoutFacade(DefaultBrainTreeCheckoutFacade acceleratorCheckoutFacade) {
        this.acceleratorCheckoutFacade = acceleratorCheckoutFacade;
    }

    public void setBraintreeConnectWithPayPalNotificationFacade(BraintreeConnectWithPayPalNotificationFacade braintreeConnectWithPayPalNotificationFacade) {
        this.braintreeConnectWithPayPalNotificationFacade = braintreeConnectWithPayPalNotificationFacade;
    }
}
