package ru.yandex.webmaster3.storage.turbo.service.preview;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Strings;
import lombok.Value;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.tuple.Pair;

import ru.yandex.webmaster3.core.turbo.model.TurboHostSettings;
import ru.yandex.webmaster3.core.turbo.model.TurboLogo;
import ru.yandex.webmaster3.core.turbo.model.TurboUserAgreement;
import ru.yandex.webmaster3.core.turbo.model.advertising.AdvertisingSettings;
import ru.yandex.webmaster3.core.turbo.model.analytics.AnalyticsSettings;
import ru.yandex.webmaster3.core.turbo.model.app.TurboAppSettings;
import ru.yandex.webmaster3.core.turbo.model.desktop.TurboDesktopSettings;
import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedSettings;
import ru.yandex.webmaster3.core.turbo.model.feedback.TurboFeedbackButton;
import ru.yandex.webmaster3.core.turbo.model.feedback.TurboFeedbackButtonType;
import ru.yandex.webmaster3.core.turbo.model.feedback.TurboFeedbackSettings;
import ru.yandex.webmaster3.storage.turbo.logo.TurboLogoData;
import ru.yandex.webmaster3.storage.turbo.service.TurboDomainsStateService.TurboDomainState;
import ru.yandex.webmaster3.storage.turbo.service.preview.app.TurboAppSettingsData;
import ru.yandex.webmaster3.storage.turbo.service.preview.commerce.HeaderParamsInfo;
import ru.yandex.webmaster3.storage.turbo.service.preview.commerce.NewCommerceSettingsData;
import ru.yandex.webmaster3.storage.turbo.service.preview.commerce.ProductInfo;
import ru.yandex.webmaster3.storage.util.JsonDBMapping;

/**
 * Created by Oleg Bazdyrev on 10/10/2017.
 */
public class TurboHostSettingsData {

    private final List<ObjectNode> analytics;
    private final List<ObjectNode> advertising;
    private final String title;
    private final Integer headerType;
    private final HeaderParamsInfo headerParams;
    private final Logo logo;
    private final List<TurboMenuItemData> menu;
    private final List<TurboMenuItemData> autoMenu;
    private final String css;
    private final Boolean autoRelated;
    private final TurboAutoRelatedSettingsData autoRelatedSettings;
    private final Boolean autoMorda;
    private final ProductInfo productInfo;
    private final FeedbackSettings feedbackSettings;
    private final TurboDesktopSettingsData desktopSettings;
    private final JsonNode experiment;
    private final TurboAuthorizationSettingsData authorization;
    private final TurboCommentsSettingsData comments;
    private final TurboSearchSettingsData search;
    private final NewCommerceSettingsData newCommerceSettings;
    private final TurboAppSettingsData appSettings;
    private final String description;
    private final String theme;
    private final Logo logoSquare;
    private final TurboDisplaySettingsData displaySettings;

    public TurboHostSettingsData(TurboHostSettings st, TurboDesktopSettings ds, TurboAppSettings as, boolean yml,
                                 TurboDomainState state, List<TurboFeedSettings> feeds) {

        this.analytics = st.getAnalyticsSettings().stream().map(AnalyticsSettings::toJson).collect(Collectors.toList());
        this.advertising = st.getAdvertisingSettingsList().stream().map(AdvertisingSettings::toJson).collect(Collectors.toList());
        this.title = st.getHeader().getTitle();
        this.headerType = st.getHeader().getType().value();
        this.headerParams = HeaderParamsInfo.fromHeaderSettings(st.getHeader());
        this.logo = Logo.fromTurboLogo(st.getHeader().getLogoInfo());
        this.menu = TurboMenuItemData.fromMenu(st.getTopMenuSettings(), false);
        this.menu.addAll(TurboMenuItemData.fromMenu(st.getMenuSettings(), !yml));
        this.autoMenu = TurboMenuItemData.fromMenu(st.getAutoMenuSettings(), true);
        this.css = ObjectUtils.firstNonNull(st.getMinifiedCss(), st.getCss());
        this.autoRelated = st.getAutoRelated();
        this.autoRelatedSettings = TurboAutoRelatedSettingsData.fromSettings(st.getAutoRelatedSettings());
        this.autoMorda = st.getAutoMorda();
        this.productInfo = ProductInfo.fromCommerceSettings(st, state);
        this.feedbackSettings = FeedbackSettings.fromTurboFeedbackSettings(st);
        this.desktopSettings = TurboDesktopSettingsData.fromDesktopSettings(st, ds);
        JsonNode experimentNode = null;
        try {
            experimentNode = Strings.isNullOrEmpty(state.getExperiment()) ? null : JsonDBMapping.OM.readTree(state.getExperiment());
        } catch (IOException e) {
            // Турбо само виновато, что прислало мусор
        }
        this.experiment = experimentNode;
        this.authorization = TurboAuthorizationSettingsData.fromSettings(st.getAuthorizationSettings());
        this.comments = TurboCommentsSettingsData.fromSettings(st.getCommentsSettings());
        this.search = yml ? null : TurboSearchSettingsData.fromSearchSettings(st.getSearchSettings());
        this.newCommerceSettings = NewCommerceSettingsData.fromInternalSettings(st, as);
        this.appSettings = TurboAppSettingsData.fromAppSettings(as, state.getAppReviewsInfoOrDefault(), st, feeds);
        this.description = as == null ? null : as.getDescription();
        this.theme = as == null ? null : as.getTurboColorsString();
        this.logoSquare = as == null ? null : Logo.fromTurboLogo(as.getLogoInfo());
        this.displaySettings = TurboDisplaySettingsData.fromSettings(st, ds);
    }

    public List<ObjectNode> getAnalytics() {
        return analytics;
    }

    public List<ObjectNode> getAdvertising() {
        return advertising;
    }

    public String getTitle() {
        return title;
    }

    @JsonProperty("header_type")
    public Integer getHeaderType() {
        return headerType;
    }

    public Logo getLogo() {
        return logo;
    }

    public List<TurboMenuItemData> getMenu() {
        return menu;
    }

    @JsonProperty("category_info")
    public List<TurboMenuItemData> getAutoMenu() {
        return autoMenu;
    }

    public String getCss() {
        return css;
    }

    @JsonProperty("auto_related")
    public Boolean getAutoRelated() {
        return autoRelated;
    }

    @JsonProperty("auto_related_settings")
    public TurboAutoRelatedSettingsData getAutoRelatedSettings() {
        return autoRelatedSettings;
    }

    @JsonProperty("auto_morda")
    public Boolean getAutoMorda() {
        return autoMorda;
    }

    @JsonProperty("product_info")
    public ProductInfo getProductInfo() {
        return productInfo;
    }

    @JsonProperty("feedback")
    public FeedbackSettings getFeedbackSettings() {
        return feedbackSettings;
    }

    @JsonProperty("desktop")
    public TurboDesktopSettingsData getDesktopSettings() {
        return desktopSettings;
    }

    @JsonProperty("experiment")
    public JsonNode getExperiment() {
        return experiment;
    }

    @JsonProperty("authorization")
    public TurboAuthorizationSettingsData getAuthorization() {
        return authorization;
    }

    @JsonProperty("header_params")
    public HeaderParamsInfo getHeaderParams() {
        return headerParams;
    }

    @JsonProperty("comments")
    public TurboCommentsSettingsData getComments() {
        return comments;
    }

    @JsonProperty("search")
    public TurboSearchSettingsData getSearch() {
        return search;
    }

    @JsonProperty("ecommerce")
    public NewCommerceSettingsData getNewCommerceSettings() {
        return newCommerceSettings;
    }

    @JsonProperty("turbo_app")
    public TurboAppSettingsData getAppSettings() {
        return appSettings;
    }

    @JsonProperty("description")
    public String getDescription() {
        return description;
    }

    @JsonProperty("theme")
    public String getTheme() {
        return theme;
    }

    @JsonProperty("logo_square")
    public Logo getLogoSquare() {
        return logoSquare;
    }

    @JsonProperty("display_params")
    public TurboDisplaySettingsData getDisplaySettings() {
        return displaySettings;
    }

    @Value
    public static final class Logo {
        private static final int DEFAULT_SIZE = 512; // for svg

        String id;
        long group;
        boolean isSvg;
        int width;
        int height;

        public static Logo fromTurboLogo(TurboLogo logoInfo) {
            if (logoInfo == null) {
                return null;
            }
            Pair<String, Long> parsedLogo = TurboLogoData.parseFrontLogoId(logoInfo.getLogoId());
            return new Logo(parsedLogo.getLeft(), parsedLogo.getRight(), logoInfo.isSvg(),
                    ObjectUtils.firstNonNull(logoInfo.getWidth(), DEFAULT_SIZE),
                    ObjectUtils.firstNonNull(logoInfo.getHeight(), DEFAULT_SIZE)
            );
        }
    }

    public static final class FeedbackSettings {

        private final String stick;
        private final List<FeedbackButton> buttons;

        public FeedbackSettings(String stick, List<FeedbackButton> buttons) {
            this.stick = stick;
            this.buttons = buttons;
        }

        @JsonProperty("stick")
        public String getStick() {
            return stick;
        }

        @JsonProperty("buttons")
        public List<FeedbackButton> getButtons() {
            return buttons;
        }

        public static FeedbackSettings fromTurboFeedbackSettings(TurboHostSettings settings) {
            TurboFeedbackSettings feedbackSettings = settings.getFeedbackSettings();
            if (feedbackSettings == null) {
                return null;
            }

            return new FeedbackSettings(feedbackSettings.getStick().name().toLowerCase(),
                    Optional.ofNullable(feedbackSettings.getButtons()).orElse(Collections.emptyList()).stream()
                            .map(button -> FeedbackButton.fromTurboFeedbackButton(button, settings.getUserAgreement()))
                            .collect(Collectors.toList()));
        }
    }

    public static final class FeedbackButton {

        private final String type;
        private final String url;
        private final String agreementCompany;
        private final String agreementLink;

        public FeedbackButton(String type, String url, String agreementCompany, String agreementLink) {
            this.type = type;
            this.url = url;
            this.agreementCompany = agreementCompany;
            this.agreementLink = agreementLink;
        }

        @JsonProperty("type")
        public String getType() {
            return type;
        }

        @JsonProperty("url")
        public String getUrl() {
            return url;
        }

        @JsonProperty("agreement_company")
        public String getAgreementCompany() {
            return agreementCompany;
        }

        @JsonProperty("agreement_link")
        public String getAgreementLink() {
            return agreementLink;
        }

        public static FeedbackButton fromTurboFeedbackButton(TurboFeedbackButton button,
                                                             TurboUserAgreement userAgreement) {
            String agreementCompany = null;
            String agreementLink = null;
            if (button.getType() == TurboFeedbackButtonType.CALLBACK && userAgreement != null) {
                agreementCompany = userAgreement.getAgreementCompany();
                agreementLink = userAgreement.getAgreementLink();
            }
            return new FeedbackButton(button.getType().name().toLowerCase(),
                    ObjectUtils.firstNonNull(button.getUrl(), button.getSendTo()), agreementCompany, agreementLink);
        }

    }

}
