package com.braintree.facade.impl;

import com.braintree.exceptions.BrainTreeUnverifiedAccountPayPalException;
import com.braintree.facade.BrainTreeRegistrationUserFacade;
import com.braintree.facade.BrainTreeSetUpPasswordFacade;
import com.braintree.hybris.data.BrainTreeConnectWithPayPalEmailData;
import com.braintree.hybris.data.BrainTreeConnectWithPayPalUserData;
import com.braintree.service.BrainTreeConnectWithPayPalService;
import de.hybris.platform.commercefacades.customer.CustomerFacade;
import de.hybris.platform.commercefacades.customer.impl.DefaultCustomerFacade;
import de.hybris.platform.commercefacades.user.data.RegisterData;
import de.hybris.platform.commerceservices.customer.DuplicateUidException;
import de.hybris.platform.core.model.user.CustomerModel;
import de.hybris.platform.servicelayer.model.ModelService;
import de.hybris.platform.servicelayer.user.UserService;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.util.Arrays;
import java.util.List;

public class DefaultBrainTreeRegistrationUserFacade implements BrainTreeRegistrationUserFacade {

    private static final Logger LOG = Logger.getLogger(DefaultBrainTreeRegistrationUserFacade.class);
    private static final String EMPTY = "";
    private static final String SPACE = " ";

    private CustomerFacade customerFacade;
    private BrainTreeConnectWithPayPalService brainTreeConnectWithPayPalService;
    private ModelService modelService;
    private UserService userService;
    private BrainTreeSetUpPasswordFacade brainTreeSetUpPasswordFacade;

    @Override
    public String registerPayPalUser(String accessToken) throws DuplicateUidException {
        final BrainTreeConnectWithPayPalUserData userData = brainTreeConnectWithPayPalService.getUserDataByAccessToken(accessToken);
        final RegisterData data = createRegistrationForm(userData);
        String payerId = StringUtils.EMPTY;
        try {
            customerFacade.register(data);
            brainTreeSetUpPasswordFacade.setPasswordForSingleAuthenticationActiveToCustomer(getEmailFromPayPalUserData(userData), false);
            setPayerIdToUser(data.getLogin().toLowerCase(), userData.getPayerId());
            payerId = userData.getPayerId();
        } catch (DuplicateUidException e) {
            LOG.error("Id for this user already exists");
            throw e;
        } catch (Exception e) {
            LOG.error("Invalid credentials", e);
        }
        return payerId;
    }

    @Override
    public void setPayerIdToUser(String id, String payerId) {
        CustomerModel customer = (CustomerModel) userService.getUserForUID(id);
        customer.setPayPalPayerId(payerId);
        modelService.save(customer);
    }

    @Override
    public String getEmailFromPayPalUserData(BrainTreeConnectWithPayPalUserData userData) {
        if (!Boolean.parseBoolean(userData.getVerifiedAccount())) {
            throw new BrainTreeUnverifiedAccountPayPalException();
        }
        return userData.getEmails().stream()
                .filter(brainTreeConnectWithPayPalEmailData -> Boolean.parseBoolean(brainTreeConnectWithPayPalEmailData.getPrimary()))
                .filter(brainTreeConnectWithPayPalEmailData -> Boolean.parseBoolean(brainTreeConnectWithPayPalEmailData.getConfirmed()))
                .map(BrainTreeConnectWithPayPalEmailData::getValue)
                .map(String::toLowerCase)
                .findFirst()
                .orElseThrow(BrainTreeUnverifiedAccountPayPalException::new);
    }

    private RegisterData createRegistrationForm(final BrainTreeConnectWithPayPalUserData userData) {
        RegisterData registerData = new RegisterData();
        registerData.setLogin(getEmailFromPayPalUserData(userData));
        registerData.setFirstName(getSplitName(userData.getName()));
        registerData.setLastName(getSplitSurname(userData.getName()));
        registerData.setPassword(EMPTY);
        return registerData;
    }

    private static String getSplitName(final String userName) {
        List<String> array = Arrays.asList(userName.split(SPACE));
        return array.stream().findFirst().orElse(EMPTY);
    }

    private static String getSplitSurname(final String userName) {
        List<String> array = Arrays.asList(userName.split(SPACE));
        return array.stream().reduce((first, second) -> second).orElse(EMPTY);
    }

    public void setCustomerFacade(DefaultCustomerFacade customerFacade) {
        this.customerFacade = customerFacade;
    }

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

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

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

    public void setBrainTreeSetUpPasswordFacade(DefaultBrainTreeSetUpPasswordFacade brainTreeSetUpPasswordFacade) {
        this.brainTreeSetUpPasswordFacade = brainTreeSetUpPasswordFacade;
    }

}
