package com.braintree.customersupportbackoffice.renderers;

import com.braintree.configuration.service.BrainTreeConfigService;
import com.braintree.customersupportbackoffice.builders.ScriptBuilder;
import com.braintree.enums.BraintreePayPalLayout;
import com.braintree.method.BrainTreePaymentService;
import com.hybris.cockpitng.core.config.impl.jaxb.editorarea.AbstractPanel;
import com.hybris.cockpitng.core.model.ModelObserver;
import com.hybris.cockpitng.core.model.WidgetModel;
import com.hybris.cockpitng.dataaccess.facades.type.DataType;
import com.hybris.cockpitng.engine.WidgetInstanceManager;
import com.hybris.cockpitng.widgets.editorarea.renderer.impl.AbstractEditorAreaPanelRenderer;
import de.hybris.platform.basecommerce.model.site.BaseSiteModel;
import de.hybris.platform.core.model.BraintreePayPalConfigurationModel;
import de.hybris.platform.core.model.BraintreePayPalStylesConfigurationModel;
import de.hybris.platform.servicelayer.session.SessionExecutionBody;
import de.hybris.platform.servicelayer.session.SessionService;
import org.apache.commons.lang.StringUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Components;
import org.zkoss.zul.Html;
import org.zkoss.zul.Div;
import org.zkoss.zul.Iframe;
import org.zkoss.zul.Script;

import java.util.Map;
import java.util.Optional;

import static com.hybris.backoffice.workflow.designer.handler.WorkflowDesignerCloseListener.VALUE_CHANGED;
import static java.util.Objects.nonNull;

public class PaypalPreviewButtonRenderer extends
        AbstractEditorAreaPanelRenderer<BraintreePayPalStylesConfigurationModel> {
    private static final String CLIENT_SCRIPT_SRC = "https://js.braintreegateway.com/web/3.97.1/js/client.min.js";
    private static final String CHECKOUT_SCRIPT_SRC = "https://js.braintreegateway.com/web/3.97.1/js/paypal-checkout.min.js";
    private static final String RENDER_PAYPAL_BUTTONS_SCRIPT = "var div = document.createElement('div');div.id = 'paypal-button-cnt'; " +
            "if (window.self !== window.top) {document.body.appendChild(div);} else " +
            "{document.getElementsByClassName('paypal-preview-button-iframe')[0].contentDocument.getElementsByTagName('body')[0].appendChild(div);}" +
            "paypal.Buttons({style: {disableMaxWidth: true, layout: '%s', color: '%s', shape: '%s', label:" +
            " '%s', height: %d, %s }, fundingSource: paypal.FUNDING.PAYPAL}).render(div);";
    private static final String OVERLAY_PAYPAL_BUTTONS_STYLE = "position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: transparent;";
    private static final String TAGLINE_TRUE = "tagline: true";
    private static final String TAGLINE_FALSE = "tagline: false";
    private static final String CURRENT_SITE = "currentSite";
    private static final String RENDER_PAY_PAL_BUTTON_JS_FUNCTION_CALL = "setTimeout(renderPayPalButton, 1000)";
    private static final String PAYPAL_PREVIEW_BUTTON_IFRAME_CLASS = "paypal-preview-button-iframe";

    private SessionService sessionService;
    private BrainTreePaymentService brainTreePaymentService;
    private BrainTreeConfigService brainTreeConfigService;

    @Override
    public void render(Component component, AbstractPanel abstractPanel,
                       BraintreePayPalStylesConfigurationModel braintreePayPalStylesConfiguration,
                       DataType dataType, WidgetInstanceManager widgetInstanceManager) {
        addPayPalButtonPreviewToComponent(component, braintreePayPalStylesConfiguration);

        WidgetModel model = widgetInstanceManager.getModel();
        model.addObserver(VALUE_CHANGED, (ModelObserver) () -> {
            BraintreePayPalStylesConfigurationModel currentRoot =
                    model.getValue(CURRENT_OBJECT_DOTLESS, BraintreePayPalStylesConfigurationModel.class);
            if (nonNull(currentRoot)) {
                Components.removeAllChildren(component);
                addPayPalButtonPreviewToComponent(component, currentRoot);
            }
        });
    }

    private void addPayPalButtonPreviewToComponent(Component component, BraintreePayPalStylesConfigurationModel braintreePayPalStylesConfiguration) {
        Iframe iframe = createIframe();
        iframe.setVflex(Boolean.TRUE.toString());
        iframe.setClass(PAYPAL_PREVIEW_BUTTON_IFRAME_CLASS);

        Script script = createScript();
        script.setContent(RENDER_PAY_PAL_BUTTON_JS_FUNCTION_CALL);
        script.setDefer(true);

        component.appendChild(iframe);
        component.appendChild(getPaypalButtons(braintreePayPalStylesConfiguration));
        component.appendChild(getOverlayForPayPalButtons());
        component.appendChild(script);
    }

    private Html getPaypalButtons(BraintreePayPalStylesConfigurationModel braintreePayPalStylesConfiguration) {
        String paypalButtons = new ScriptBuilder()
                .setSrc(CLIENT_SCRIPT_SRC)
                .setCheckoutSrc(CHECKOUT_SCRIPT_SRC)
                .setOnLoadMethod(getPayPalButton(braintreePayPalStylesConfiguration))
                .setAuthorizationId(getAuthorizationId(braintreePayPalStylesConfiguration.getBraintreePayPalConfiguration()))
                .buildScript();
        return createHtml(paypalButtons);
    }

    private String getAuthorizationId(BraintreePayPalConfigurationModel braintreePayPalConfigurationModel) {
        String authorizationId = StringUtils.EMPTY;

        Optional<BaseSiteModel> baseSiteModel = brainTreeConfigService
                .getBaseSiteForPayPalConfigurationId(braintreePayPalConfigurationModel.getBraintreePayPalConfigurationId());
        if (baseSiteModel.isPresent()) {
            authorizationId = sessionService.executeInLocalViewWithParams(Map.of(CURRENT_SITE, baseSiteModel.get()), new SessionExecutionBody() {
                @Override
                public Object execute() {
                    return brainTreePaymentService.generateClientToken(StringUtils.EMPTY);
                }
            });
        }
        return authorizationId;
    }

    private String getPayPalButton(BraintreePayPalStylesConfigurationModel model) {
        return String.format(RENDER_PAYPAL_BUTTONS_SCRIPT, model.getLayout().getCode().toLowerCase(),
                model.getColor().getCode().toLowerCase(), model.getShape().getCode().toLowerCase(),
                model.getLabel().getCode().toLowerCase(), model.getHeight(), getTagline(model));
    }

    private String getTagline(BraintreePayPalStylesConfigurationModel model) {
        if (model.getLayout().equals(BraintreePayPalLayout.HORIZONTAL) && model.isTagline()) {
            return TAGLINE_TRUE;
        } else {
            return TAGLINE_FALSE;
        }
    }

    private Div getOverlayForPayPalButtons() {
        Div overlay = createDiv();
        overlay.setStyle(OVERLAY_PAYPAL_BUTTONS_STYLE);
        return overlay;
    }

    protected Div createDiv() {
        return new Div();
    }

    protected Script createScript() {
        return new Script();
    }

    protected Iframe createIframe() {
        return new Iframe();
    }

    protected Html createHtml(String content) {
        return new Html(content);
    }

    public void setBrainTreePaymentService(BrainTreePaymentService brainTreePaymentService) {
        this.brainTreePaymentService = brainTreePaymentService;
    }

    public void setSessionService(SessionService sessionService) {
        this.sessionService = sessionService;
    }

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