package com.braintree.controllers.pages;

import com.braintree.configuration.service.BrainTreeConfigService;
import com.braintree.controllers.handler.BraintreePayPalResponseExpressCheckoutHandler;
import com.braintree.enums.BrainTreePaymentMethod;
import com.braintree.enums.BraintreePageType;
import com.braintree.exceptions.BrainTreeConnectWithPayPalException;
import com.braintree.exceptions.BrainTreeUnverifiedAccountPayPalException;
import com.braintree.facade.BrainTreeConnectWithPayPalFacade;
import com.braintree.facade.BrainTreeRegistrationUserFacade;
import com.braintree.facade.BrainTreeUserFacade;
import com.braintree.facade.BraintreeConnectWithPayPalNotificationFacade;
import com.braintree.facade.BraintreeConfigurationFacade;
import com.braintree.facade.impl.DefaultBrainTreeCheckoutFacade;
import com.braintree.facade.impl.DefaultBrainTreePaymentFacade;
import com.braintree.hybris.data.BrainTreeConnectWithPayPalAddressData;
import com.braintree.hybris.data.BrainTreeConnectWithPayPalUserData;
import com.braintree.hybris.data.BrainTreeSubscriptionInfoData;
import com.braintree.hybris.data.BraintreeCheckoutData;
import com.braintree.hybris.data.PayPalDetails;
import com.braintree.hybris.data.PayPalExpressResponse;
import com.braintree.method.BrainTreePaymentService;
import com.braintree.hybris.data.BrainTreeConnectWithPayPalUserData;
import com.braintree.hybris.data.BrainTreeConnectWithPayPalEmailData;
import com.braintree.security.PayPalAutoLoginStrategy;
import com.braintree.util.BrainTreeUtils;
import com.braintree.util.GenericBuilder;
import de.hybris.platform.acceleratorfacades.flow.CheckoutFlowFacade;
import de.hybris.platform.acceleratorstorefrontcommons.controllers.pages.AbstractLoginPageController;
import de.hybris.platform.acceleratorstorefrontcommons.controllers.util.GlobalMessages;
import de.hybris.platform.acceleratorstorefrontcommons.forms.GuestForm;
import de.hybris.platform.acceleratorstorefrontcommons.forms.LoginForm;
import de.hybris.platform.acceleratorstorefrontcommons.forms.RegisterForm;
import de.hybris.platform.cms2.exceptions.CMSItemNotFoundException;
import de.hybris.platform.cms2.model.pages.AbstractPageModel;
import de.hybris.platform.cms2.model.pages.ContentPageModel;
import de.hybris.platform.commercefacades.order.data.CartData;
import de.hybris.platform.commercefacades.user.data.AddressData;
import de.hybris.platform.commercefacades.user.data.CustomerData;
import de.hybris.platform.commerceservices.customer.DuplicateUidException;
import de.hybris.platform.servicelayer.session.SessionService;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;

import static com.braintree.constants.BraintreeConstants.PropertyConfiguration.BRAINTREE_ACCEPTED_CREDIT_CARD_PAYMENT_METHODS;
import static com.braintree.controllers.BraintreeaddonControllerConstants.BRAINTREE_PAYPAL_CONNECT_GLOBAL_ERROR;
import static com.braintree.controllers.BraintreeaddonControllerConstants.BRAINTREE_THE_PASSWORD_IS_NOT_CORRECT_ERROR;
import static com.braintree.controllers.BraintreeaddonControllerConstants.BRAINTREE_USER_ACCOUNT_HAS_BEEN_DISABLED_ERROR;
import static com.braintree.controllers.BraintreeaddonControllerConstants.BRAINTREE_PAYPAL_CONNECT_LOGIN_LINKED_ACCOUNTS;
import static com.braintree.controllers.BraintreeaddonControllerConstants.BRAINTREE_PAYPAL_CONNECT_REGISTRATION_MESSAGE_SET_UP_PASSWORD_FOR_NEW_USER;
import static com.braintree.controllers.BraintreeaddonControllerConstants.CHECKOUT_MULTI_DELIVERY_ADDRESS_ADD;
import static com.braintree.controllers.BraintreeaddonControllerConstants.DISABLE_LOGIN_VIA_PAYPAL_TO_THE_EXISTING_USER_MESSAGE;
import static com.braintree.controllers.BraintreeaddonControllerConstants.IS_USER_LOGGING_IN_FROM_LOGIN_PAGE;
import static com.braintree.controllers.BraintreeaddonControllerConstants.PREPARATION_FOR_LINK_PAYPAL_ACCOUNT;
import static com.braintree.controllers.BraintreeaddonControllerConstants.BRAINTREE_CHECKOUT_DATA;
import static com.braintree.controllers.BraintreeaddonControllerConstants.BRAINTREE_CONFIG_DATA;
import static com.braintree.controllers.BraintreeaddonControllerConstants.Views.Pages.Login.SAVE_PAYMENT_INFO_PAGE;
import static com.braintree.controllers.BraintreeaddonControllerConstants.Views.Pages.Login.CONNECT_WITH_PAYPAL_SECURITY_LAYER_PAGE;
import static com.braintree.controllers.BraintreeaddonControllerConstants.Views.Pages.Account.AccountLoginPage;
import static com.braintree.controllers.BraintreeaddonControllerConstants.Views.Pages.Checkout.CheckoutLoginPage;
import static de.hybris.platform.util.localization.Localization.getLocalizedString;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Optional;

@Controller
@RequestMapping(value = "/connect/login")
public class BrainTreeConnectWithPayPalController extends AbstractLoginPageController {

    private static final Logger LOG = Logger.getLogger(BrainTreeConnectWithPayPalController.class);
    private static final String PAYER_ID = "payerId";
    private static final String ADDRESS_DATA = "addressData";
    private static final String IS_REQUEST_FROM_CHECKOUT_PAGE = "isRequestFromCheckoutPage";
    private static final String SHOULD_SAVE_ADDRESS = "shouldSaveAddress";
    private static final String SHOULD_SAVE_PAYMENT_INFO = "shouldSavePaymentInfo";
    private static final String PAYPAL_CONNECT_SERVLET_PATH = "/checkout";
    public static final String USER_EMAIL = "userEmail";
    public static final String MESSAGE = "message";
    private static final String USER_DATA_ATTRIBUTE = "userData";
    private static final String BASE_SITE_NAME_ATTRIBUTE = "baseSiteName";
    private static final String SAVE_ADDRESS_AND_PAYMENT_INFOS = "saveAddressAndPaymentInfos";
    private static final String SAVE_ADDRESS_AND_PAYMENT_INFOS_URL = "connect/login/saveAddressAndPaymentInfos";
    private static final String SAVE_ADDRESS_AND_PAYMENT_INFOS_CHECKOUT_URL = "connect/login/saveAddressAndPaymentInfos/checkout";
    private static final String NOT_SAVE_PAYMENT_AND_ADDRESS_INFOS = "notSavePaymentAndAddressInfos";
    private static final String NOT_SAVE_PAYMENT_AND_ADDRESS_INFOS_URL = "connect/login/notSavePaymentAndAddressInfos";
    private static final String NOT_SAVE_PAYMENT_AND_ADDRESS_INFOS_CHECKOUT_URL = "connect/login/notSavePaymentAndAddressInfos/checkout";
    private static final String CONNECT_WITH_PAYPAL_SECURITY_LAYER = "/connect/login/verify-password";
    public static final String REDIRECT = "redirect:";
    private static final String LOGIN_PAGE_REDIRECT = REDIRECT + "/login";
    private static final String UNVERIFIED_ACCOUNT_ERROR = "braintree.paypal.unverified.account.error";

    @Resource(name = "brainTreePaymentFacadeImpl")
    private DefaultBrainTreePaymentFacade brainTreePaymentFacade;
    @Resource(name = "httpSessionRequestCache")
    private HttpSessionRequestCache httpSessionRequestCache;

    @Resource(name = "braintreePayPalResponseExpressCheckoutHandler")
    BraintreePayPalResponseExpressCheckoutHandler braintreePayPalResponseExpressCheckoutHandler;

    @Resource(name = "sessionService")
    private SessionService sessionService;

    @Resource(name = "checkoutFlowFacade")
    private CheckoutFlowFacade checkoutFlowFacade;

    @Resource(name = "brainTreeConnectWithPayPalFacade")
    private BrainTreeConnectWithPayPalFacade brainTreeConnectWithPayPalFacade;

    @Resource(name = "braintreeConnectWithPayPalNotificationFacade")
    private BraintreeConnectWithPayPalNotificationFacade braintreeConnectWithPayPalNotificationFacade;

    @Resource(name = "brainTreeRegistrationUserFacade")
    private BrainTreeRegistrationUserFacade userFacade;

    @Resource(name = "defaultBraintreeConfigurationFacade")
    private BraintreeConfigurationFacade brainTreeConfigFacade;

    @Resource(name = "payPalAutoLoginStrategy")
    private PayPalAutoLoginStrategy payPalAutoLoginStrategy;

    @Resource(name = "userFacade")
    private BrainTreeUserFacade brainTreeUserFacade;

    @Resource(name = "brainTreeConfigService")
    private BrainTreeConfigService brainTreeConfigService;

    @Resource(name = "brainTreeCheckoutFacade")
    private DefaultBrainTreeCheckoutFacade brainTreeCheckoutFacade;

    @Resource(name = "brainTreePaymentService")
    private BrainTreePaymentService brainTreePaymentService;

    public static final String CONNECT_LOGIN_SAVE_PAYMENT_INFO_AND_ADDRESS_PAGE = "/connect/login/savePaymentInfoAndAddressPage";


    @RequestMapping(method = RequestMethod.GET)
    public String doLogin(@RequestHeader(value = "referer", required = false) final String referer,
        final RegisterForm form, final Model model,
        final HttpServletRequest request, final HttpServletResponse response,
        @RequestParam(required = false) String code, HttpSession session, final RedirectAttributes redirectAttributes)
        throws CMSItemNotFoundException {
        sessionService.setAttribute(IS_USER_LOGGING_IN_FROM_LOGIN_PAGE, true);
        storeReferer(referer, request, response);
        return processRequest(model, form, request, response, session,  code, redirectAttributes);
    }

    @RequestMapping(value = "/checkout", method = RequestMethod.GET)
    public String doCheckoutLogin(final Model model, final RegisterForm form, final HttpServletRequest request,
        final HttpServletResponse response, @RequestParam(required = false) final String code,
        HttpSession session, final RedirectAttributes redirectAttributes) throws CMSItemNotFoundException {
        sessionService.setAttribute(IS_USER_LOGGING_IN_FROM_LOGIN_PAGE, false);
        model.addAttribute("expressCheckoutAllowed",
            Boolean.valueOf(checkoutFlowFacade.isExpressCheckoutEnabledForStore()));
        return processRequest(model, form, request, response, session, code, redirectAttributes);
    }

    @PostMapping(value = {"/saveAddressAndPaymentInfos", "/saveAddressAndPaymentInfos/checkout"})
    public String doHandlePayPalResponse(final HttpServletRequest request, final HttpServletResponse response,
                                         final Model model, RedirectAttributes redirectAttributes) {
        final String payerId = sessionService.getAttribute(PAYER_ID);
        final String email = sessionService.getAttribute(USER_EMAIL);
        final BrainTreeConnectWithPayPalAddressData addressData = sessionService.getAttribute(ADDRESS_DATA);
        if ((boolean) sessionService.getAttribute(SHOULD_SAVE_PAYMENT_INFO)) {
            try {
                savePayPalPayment(request, email);
                GlobalMessages.addFlashMessage(redirectAttributes, GlobalMessages.CONF_MESSAGES_HOLDER, "paypal.connect.saved.payment.method");
            }catch (Exception e){
                LOG.error("Error during adding payment method for new customer", e);
                GlobalMessages.addFlashMessage(redirectAttributes, GlobalMessages.INFO_MESSAGES_HOLDER, "paypal.connect.saved.payment.method.error");
            }
        }

        if ((boolean) sessionService.getAttribute(SHOULD_SAVE_ADDRESS)) {
            try {
                if (addressData != null) {
                    brainTreeConnectWithPayPalFacade.addAddressForNewUser(addressData, email);
                    GlobalMessages.addFlashMessage(redirectAttributes, GlobalMessages.CONF_MESSAGES_HOLDER, "paypal.connect.saved.address");
                }
            } catch (Exception e) {
                LOG.error("Error during adding address for new customer", e);
                GlobalMessages.addFlashMessage(redirectAttributes, GlobalMessages.INFO_MESSAGES_HOLDER, "paypal.connect.saved.address.error");
            }
        }
        GlobalMessages.addFlashMessage(redirectAttributes,
                GlobalMessages.CONF_MESSAGES_HOLDER,
                getLocalizedString(sessionService.getAttribute(MESSAGE)),
                null);
        removeSessionAttribute();
        return processLogin(request, response, payerId);
    }

    @PostMapping(value = {"/notSavePaymentAndAddressInfos", "/notSavePaymentAndAddressInfos/checkout"})
    public String doSavePaymentInfo(final RegisterForm form, final HttpServletRequest request,
                                    final HttpServletResponse response,
                                    final Model model) {
        model.addAttribute(form);
        final String payerId = sessionService.getAttribute(PAYER_ID);
        GlobalMessages.addFlashMessage(RequestContextUtils.getOutputFlashMap(request),
                GlobalMessages.CONF_MESSAGES_HOLDER,
                getLocalizedString(sessionService.getAttribute(MESSAGE)),
                null);
        removeSessionAttribute();
        return processLogin(request, response, payerId);
    }

    @RequestMapping(value = "/savePaymentInfoAndAddressPage", method = RequestMethod.GET)
    public String getSavePaymentInfoAndAddressPage(final Model model, HttpServletRequest request) throws CMSItemNotFoundException {
        setModelAttributesForPaymentAndAddressInfo(request, model);
        storeCmsPageInModel(model, getCmsPage());
        setUpMetaDataForContentPage(model, (ContentPageModel) getCmsPage());
        return SAVE_PAYMENT_INFO_PAGE;
    }

    private String processRequest(Model model, RegisterForm form, HttpServletRequest request,
        HttpServletResponse response, HttpSession session, String code, RedirectAttributes redirectAttributes) throws CMSItemNotFoundException {
        if (code == null) {
            return getDefaultLoginPage(false, session, model);
        }
        BrainTreeConnectWithPayPalUserData userData;
        String accessToken;
        String email;
        try {
            accessToken = brainTreeConnectWithPayPalFacade.exchangeAuthorizationCodeToAccessToken(code);
            userData = brainTreeConnectWithPayPalFacade.getUserDataByAccessToken(accessToken);
            email = userFacade.getEmailFromPayPalUserData(userData);
        } catch (BrainTreeUnverifiedAccountPayPalException e) {
            LOG.error(String.format("Unverified PayPal account : %s", e.getMessage()), e);
            GlobalMessages.addFlashMessage(redirectAttributes,
                    GlobalMessages.ERROR_MESSAGES_HOLDER,
                    getLocalizedString(UNVERIFIED_ACCOUNT_ERROR));
            return LOGIN_PAGE_REDIRECT;
        } catch (BrainTreeConnectWithPayPalException e) {
            LOG.error(String.format("Exception raised in getRegister method : %s", e.getMessage()), e);
            return getDefaultLoginPage(false, session, model);
        }
        
        if (brainTreeUserFacade.isUserExisting(email)) {
            if (!brainTreeUserFacade.isCustomerWithPayerIdExist(userData.getPayerId())) {
                if(!brainTreeConfigService.isEnableLoginViaPayPalToTheExistingUser()){
                    GlobalMessages.addFlashMessage(RequestContextUtils.getOutputFlashMap(request),
                            GlobalMessages.ERROR_MESSAGES_HOLDER,
                            getLocalizedString(DISABLE_LOGIN_VIA_PAYPAL_TO_THE_EXISTING_USER_MESSAGE), null);
                    return LOGIN_PAGE_REDIRECT;
                }

                sessionService.setAttribute(USER_DATA_ATTRIBUTE, userData);
                if (brainTreeConfigService.isPayPalLippAdditionalSecurityEnable()) {
                    return REDIRECT + CONNECT_WITH_PAYPAL_SECURITY_LAYER;
                } else {
                    return REDIRECT + PREPARATION_FOR_LINK_PAYPAL_ACCOUNT;
                }
            }
            return processLogin(request, response, userData.getPayerId());
        } else {
            try {
                userFacade.registerPayPalUser(accessToken);
                final boolean shutSavePaymentInfo = brainTreeConnectWithPayPalFacade.shouldSavePayPalPaymentInfo();
                if(brainTreeConfigService.isPayPalConnectAddPaymentMethodFlow()){
                    setSessionAttributeForPaymentAndAddressInfo(
                            BRAINTREE_PAYPAL_CONNECT_REGISTRATION_MESSAGE_SET_UP_PASSWORD_FOR_NEW_USER,
                            true, shutSavePaymentInfo, userData, email, request);
                    return REDIRECT + CONNECT_LOGIN_SAVE_PAYMENT_INFO_AND_ADDRESS_PAGE;
                }
                GlobalMessages.addFlashMessage(RequestContextUtils.getOutputFlashMap(request),
                        GlobalMessages.CONF_MESSAGES_HOLDER,
                        getLocalizedString(BRAINTREE_PAYPAL_CONNECT_REGISTRATION_MESSAGE_SET_UP_PASSWORD_FOR_NEW_USER),
                        null);
                return processLogin(request, response, userData.getPayerId());
            } catch (BrainTreeUnverifiedAccountPayPalException e) {
                LOG.error(String.format("Unverified PayPal account : %s", e.getMessage()), e);
                GlobalMessages.addFlashMessage(redirectAttributes,
                        GlobalMessages.ERROR_MESSAGES_HOLDER,
                        getLocalizedString(UNVERIFIED_ACCOUNT_ERROR));
                return getDefaultLoginPage(false, session, model);
            } catch (DuplicateUidException e) {
                form.setTermsCheck(false);
                model.addAttribute(form);
                model.addAttribute(new LoginForm());
                model.addAttribute(new GuestForm());
                GlobalMessages.addErrorMessage(model, BRAINTREE_PAYPAL_CONNECT_GLOBAL_ERROR);
                return handleRegistrationError(model, request);
            }
        }
    }

    @RequestMapping(value = "/verify-password", method = RequestMethod.GET)
    public String connectWithPayPalSecurityLayer(final Model model,
                                                 @RequestParam(required = false) final boolean securityIsFailed)
            throws CMSItemNotFoundException {

        BrainTreeConnectWithPayPalUserData userData = sessionService.getAttribute(USER_DATA_ATTRIBUTE);
        String email = userFacade.getEmailFromPayPalUserData(userData);

        model.addAttribute(USER_EMAIL, email);
        model.addAttribute(BASE_SITE_NAME_ATTRIBUTE, getBaseSiteService().getCurrentBaseSite().getName());

        storeCmsPageInModel(model, getCmsPage());
        setUpMetaDataForContentPage(model, (ContentPageModel) getCmsPage());

        if (brainTreeUserFacade.isLoginDisabledForCurrentEmail(email)) {
            GlobalMessages.addErrorMessage(model, BRAINTREE_USER_ACCOUNT_HAS_BEEN_DISABLED_ERROR);
        } else if (securityIsFailed) {
            GlobalMessages.addErrorMessage(model, BRAINTREE_THE_PASSWORD_IS_NOT_CORRECT_ERROR);
        }

        return CONNECT_WITH_PAYPAL_SECURITY_LAYER_PAGE;
    }

    @RequestMapping(value = "/preparationForLinkPayPalAccount", method = RequestMethod.GET)
    public String preparationForLinkPayPalAccount(final HttpServletRequest request, final HttpServletResponse response) {
        BrainTreeConnectWithPayPalUserData userData = sessionService.getAttribute(USER_DATA_ATTRIBUTE);
        sessionService.removeAttribute(USER_DATA_ATTRIBUTE);
        String email = userFacade.getEmailFromPayPalUserData(userData);

        userFacade.setPayerIdToUser(email, userData.getPayerId());
        braintreeConnectWithPayPalNotificationFacade.sendLinkCustomerEmailNotification(email);
        final boolean isPayPalAddressPresent = brainTreeConnectWithPayPalFacade.isPayPalAddressPresent(email, userData.getAddress());
        final boolean isPayPalPaymentMethodPresent = brainTreeConnectWithPayPalFacade.isPayPalPaymentMethodPresentForConnectWithPayPal(email);

        if (brainTreeConfigService.isPayPalConnectAddPaymentMethodFlow() && !paypalMethodAndAddressPresent(isPayPalAddressPresent, isPayPalPaymentMethodPresent)) {
            setSessionAttributeForPaymentAndAddressInfo(BRAINTREE_PAYPAL_CONNECT_LOGIN_LINKED_ACCOUNTS,
                    !isPayPalAddressPresent, !isPayPalPaymentMethodPresent, userData, email, request);
            return REDIRECT + CONNECT_LOGIN_SAVE_PAYMENT_INFO_AND_ADDRESS_PAGE;
        }
        GlobalMessages.addFlashMessage(RequestContextUtils.getOutputFlashMap(request),
                GlobalMessages.INFO_MESSAGES_HOLDER,
                getLocalizedString(BRAINTREE_PAYPAL_CONNECT_LOGIN_LINKED_ACCOUNTS), null);

        return processLogin(request, response, userData.getPayerId());
    }

    private String processLogin(final HttpServletRequest request, final HttpServletResponse response,
        final String payerId) {
        final CustomerData customer = brainTreeUserFacade.getCustomerByPayerId(payerId);
        payPalAutoLoginStrategy.login(customer.getUid(), request, response);
        return "redirect:" + this.getSuccessRedirect(request, response);
    }

    @Override
    protected AbstractPageModel getCmsPage() throws CMSItemNotFoundException {
        final boolean isLoginPage = sessionService.getAttribute(IS_USER_LOGGING_IN_FROM_LOGIN_PAGE);
        if (isLoginPage) {
            return getContentPageForLabelOrId("login");
        }
        return getContentPageForLabelOrId("checkout-login");
    }

    @Override
    protected String getSuccessRedirect(final HttpServletRequest request, final HttpServletResponse response) {
        if (isRequestFromCheckoutPage(request)) {
            if (hasItemsInCart()) {
                return CHECKOUT_MULTI_DELIVERY_ADDRESS_ADD;
            }
            return PAYPAL_CONNECT_SERVLET_PATH;
        }
        if (httpSessionRequestCache.getRequest(request, response) != null) {
            return httpSessionRequestCache.getRequest(request, response).getRedirectUrl();
        }
        return "/";
    }

    private boolean isRequestFromCheckoutPage(final HttpServletRequest request) {
        return request.getServletPath().contains(PAYPAL_CONNECT_SERVLET_PATH);
    }

    private boolean hasItemsInCart() {
        final CartData cartData = checkoutFlowFacade.getCheckoutCart();
        return cartData.getEntries() != null && !cartData.getEntries().isEmpty();
    }

    @Override
    protected String getView() {
        final boolean isLoginPage = sessionService.getAttribute(IS_USER_LOGGING_IN_FROM_LOGIN_PAGE);
        sessionService.removeAttribute(IS_USER_LOGGING_IN_FROM_LOGIN_PAGE);
        if (isLoginPage) {
            return AccountLoginPage;
        }
        return CheckoutLoginPage;
    }

    protected void storeReferer(final String referer, final HttpServletRequest request,
        final HttpServletResponse response) {
        if (StringUtils.isNotBlank(referer) && !StringUtils.endsWith(referer, "/connect/login")
            && referer.startsWith(request.getServerName())) {
            httpSessionRequestCache.saveRequest(request, response);
        }
    }

    private String handleRegistrationError(final Model model, final HttpServletRequest request)
        throws CMSItemNotFoundException {
        String view;
        ContentPageModel pageModel;
        if (isRequestFromCheckoutPage(request)) {
            pageModel = getContentPageForLabelOrId("checkout-login");
            view = CheckoutLoginPage;
        } else {
            pageModel = getContentPageForLabelOrId("login");
            view = AccountLoginPage;
        }
        storeCmsPageInModel(model, pageModel);
        setUpMetaDataForContentPage(model, pageModel);
        addRegistrationConsentDataToModel(model);
        return view;
    }

    private void setSessionAttributeForPaymentAndAddressInfo(final String message,
                                                             final boolean shutSaveAddress,
                                                             final boolean shutSavePaymentInfo,
                                                             final BrainTreeConnectWithPayPalUserData userData,
                                                             final String email,
                                                             final HttpServletRequest request) {

        sessionService.setAttribute(MESSAGE, message);
        sessionService.setAttribute(SHOULD_SAVE_ADDRESS, shutSaveAddress);
        sessionService.setAttribute(SHOULD_SAVE_PAYMENT_INFO, shutSavePaymentInfo);
        sessionService.setAttribute(PAYER_ID, userData.getPayerId());
        sessionService.setAttribute(ADDRESS_DATA, userData.getAddress());
        sessionService.setAttribute(IS_REQUEST_FROM_CHECKOUT_PAGE, isRequestFromCheckoutPage(request));
        sessionService.setAttribute(USER_EMAIL, email);
    }

    private void removeSessionAttribute() {
        sessionService.removeAttribute(MESSAGE);
        sessionService.removeAttribute(PAYER_ID);
        sessionService.removeAttribute(ADDRESS_DATA);
        sessionService.removeAttribute(SHOULD_SAVE_ADDRESS);
        sessionService.removeAttribute(SHOULD_SAVE_PAYMENT_INFO);
        sessionService.removeAttribute(IS_REQUEST_FROM_CHECKOUT_PAGE);
        sessionService.removeAttribute(USER_EMAIL);
    }

    private void setModelAttributesForPaymentAndAddressInfo(HttpServletRequest request, Model model) {
        final BraintreeCheckoutData checkoutData = brainTreeCheckoutFacade.getBraintreeCheckoutData(BraintreePageType.LOGIN);
        model.addAttribute(BRAINTREE_CHECKOUT_DATA, checkoutData);
        model.addAttribute(BRAINTREE_CONFIG_DATA, brainTreeConfigFacade.getBraintreePluginConfigurationData());
        model.addAttribute(SHOULD_SAVE_ADDRESS, sessionService.getAttribute(SHOULD_SAVE_ADDRESS));
        model.addAttribute(SHOULD_SAVE_PAYMENT_INFO, sessionService.getAttribute(SHOULD_SAVE_PAYMENT_INFO));
        if ((boolean) sessionService.getAttribute(IS_REQUEST_FROM_CHECKOUT_PAGE)) {
            model.addAttribute(NOT_SAVE_PAYMENT_AND_ADDRESS_INFOS, NOT_SAVE_PAYMENT_AND_ADDRESS_INFOS_CHECKOUT_URL);
            model.addAttribute(SAVE_ADDRESS_AND_PAYMENT_INFOS, SAVE_ADDRESS_AND_PAYMENT_INFOS_CHECKOUT_URL);
        } else {
            model.addAttribute(NOT_SAVE_PAYMENT_AND_ADDRESS_INFOS, NOT_SAVE_PAYMENT_AND_ADDRESS_INFOS_URL);
            model.addAttribute(SAVE_ADDRESS_AND_PAYMENT_INFOS, SAVE_ADDRESS_AND_PAYMENT_INFOS_URL);
        }
    }

    private void savePayPalPayment(final HttpServletRequest request, String email){
        PayPalExpressResponse payPalExpressResponse;
        AddressData hybrisBillingAddress;
        payPalExpressResponse = braintreePayPalResponseExpressCheckoutHandler.handlePayPalResponse(request);
        String payPalEmail = payPalExpressResponse.getDetails().getEmail();
        if (Optional.ofNullable(payPalExpressResponse.getDetails()).map(PayPalDetails::getBillingAddress).isPresent()) {
            hybrisBillingAddress = braintreePayPalResponseExpressCheckoutHandler.getPayPalAddress(
                    payPalExpressResponse.getDetails(), payPalExpressResponse.getDetails().getBillingAddress());
            hybrisBillingAddress.setEmail(payPalExpressResponse.getDetails().getEmail());
        } else {
            hybrisBillingAddress = new AddressData();
            hybrisBillingAddress.setEmail(payPalEmail);
        }

        final BrainTreeSubscriptionInfoData paymentInfoData = GenericBuilder.of(BrainTreeSubscriptionInfoData::new)
                .with(BrainTreeSubscriptionInfoData::setEmail, payPalEmail)
                .with(BrainTreeSubscriptionInfoData::setNonce, payPalExpressResponse.getNonce())
                .with(BrainTreeSubscriptionInfoData::setSavePaymentInfo, true)
                .with(BrainTreeSubscriptionInfoData::setAddressData, hybrisBillingAddress)
                .build();

        brainTreePaymentFacade.createPaymentInfoForLogin(paymentInfoData, email);
    }

    private boolean paypalMethodAndAddressPresent(boolean isPayPalPaymentMethodPresent, boolean isPayPalAddressPresent) {
        return isPayPalPaymentMethodPresent && isPayPalAddressPresent;
    }
}
