package ru.yandex.webmaster3.core.turbo.model;

import java.net.URISyntaxException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.common.base.Strings;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.http.client.utils.URIBuilder;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.turbo.model.advertising.AdvertisingPlacement;
import ru.yandex.webmaster3.core.turbo.model.advertising.AdvertisingSettings;
import ru.yandex.webmaster3.core.turbo.model.advertising.AdvertisingSettingsMapDeserializer;
import ru.yandex.webmaster3.core.turbo.model.analytics.AnalyticsSettings;
import ru.yandex.webmaster3.core.turbo.model.authorization.TurboAuthorizationSettings;
import ru.yandex.webmaster3.core.turbo.model.comments.TurboCommentsSettings;
import ru.yandex.webmaster3.core.turbo.model.commerce.TurboCommerceSettings;
import ru.yandex.webmaster3.core.turbo.model.feedback.TurboFeedbackSettings;
import ru.yandex.webmaster3.core.turbo.model.menu.AutoMenuSettingsDeserializer;
import ru.yandex.webmaster3.core.turbo.model.menu.TurboMenuItem;
import ru.yandex.webmaster3.core.turbo.model.search.TurboSearchSettings;

/**
 * Турбо-настройки для конкретного хоста
 * Created by Oleg Bazdyrev on 05/07/2017.
 */
@Getter
public class TurboHostSettings {

    @JsonProperty("header")
    @Description("Настройки заголовка")
    TurboHostHeader header;
    @JsonProperty("advertisingSettings")
    @JsonDeserialize(using = AdvertisingSettingsMapDeserializer.class)
    @Description("Настройки рекламных кампаний")
    Map<AdvertisingPlacement, List<AdvertisingSettings>> advertisingSettings;
    @Description("Настройки аналитики")
    @JsonProperty("analyticsSettings")
    List<AnalyticsSettings> analyticsSettings;
    @JsonProperty("accessSettings")
    @Description("Настройки авторизации")
    TurboAccessSettings accessSettings;
    @JsonProperty("menuSettings")
    @Description("Пункты меню")
    List<TurboMenuItem> menuSettings;
    @JsonProperty("feedbackSettings")
    @Description("Настройки блока обратной связи")
    TurboFeedbackSettings feedbackSettings;
    @JsonProperty("css")
    @Description("Кастомный css для сайта")
    String css;
    @JsonProperty("minifiedCss")
    @Description("Минифицированный css")
    String minifiedCss;
    @JsonProperty("autoRelated")
    @Description("Включена ли бесконечная лента для сайта")
    Boolean autoRelated;
    @JsonProperty("autoRelatedSettings")
    @Description("Настройки бесконечной ленты для сайта")
    TurboAutoRelatedSettings autoRelatedSettings;
    @JsonProperty("eCommerceSettings")
    @Description("Настройки e-commerce")
    TurboCommerceSettings commerceSettings;
    @JsonProperty("userAgreement")
    @Description("Настройки пользовательского соглашения (для кнопки обратной связи и кнопки 'Купить в один клик'")
    TurboUserAgreement userAgreement;
    @JsonProperty("searchSettings")
    @Description("Настройки поиска")
    TurboSearchSettings searchSettings;
    @JsonProperty("topMenuSettings")
    @Description("Верхнее меню")
    List<TurboMenuItem> topMenuSettings;
    @JsonProperty("authorizationSettings")
    @Description("Настройки ручек для авторизации")
    TurboAuthorizationSettings authorizationSettings;
    @JsonProperty("commentsSettings")
    @Description("Настройки ручек для комментариев")
    TurboCommentsSettings commentsSettings;
    @JsonProperty("autoMorda")
    @Description("Включена ли автоморда")
    Boolean autoMorda;
    @JsonProperty("autoMenuSettings")
    @Description("Автоменю (е-коммерс)")
    @JsonDeserialize(using = AutoMenuSettingsDeserializer.class)
    List<TurboMenuItem> autoMenuSettings;
    @JsonProperty("displaySettings")
    @Description("Настройки отображения (для контентного Турбо)")
    TurboDisplaySettings displaySettings;

    @JsonCreator
    public TurboHostSettings(@JsonProperty("header") TurboHostHeader header,
                             @JsonProperty("advertisingSettings") @JsonDeserialize(using = AdvertisingSettingsMapDeserializer.class)
                                     Map<AdvertisingPlacement, List<AdvertisingSettings>> advertisingSettings,
                             @JsonProperty("analyticsSettings") List<AnalyticsSettings> analyticsSettings,
                             @JsonProperty("accessSettings") TurboAccessSettings accessSettings,
                             @JsonProperty("menuSettings") List<TurboMenuItem> menuSettings,
                             @JsonProperty("feedbackSettings") TurboFeedbackSettings feedbackSettings,
                             @JsonProperty("css") String css, @JsonProperty("minifiedCss") String minifiedCss,
                             @JsonProperty("autoRelated") Boolean autoRelated,
                             @JsonProperty("autoRelatedSettings") TurboAutoRelatedSettings autoRelatedSettings,
                             @JsonProperty("eCommerceSettings") TurboCommerceSettings commerceSettings,
                             @JsonProperty("userAgreement") TurboUserAgreement userAgreement,
                             @JsonProperty("searchSettings") TurboSearchSettings searchSettings,
                             @JsonProperty("topMenuSettings") List<TurboMenuItem> topMenuSettings,
                             @JsonProperty("authorizationSettings") TurboAuthorizationSettings authorizationSettings,
                             @JsonProperty("commentsSettings") TurboCommentsSettings commentsSettings,
                             @JsonProperty("autoMorda") Boolean autoMorda,
                             @JsonProperty("autoMenuSettings") List<TurboMenuItem> autoMenuSettings,
                             @JsonProperty("displaySettings") TurboDisplaySettings displaySettings) {
        this.header = header == null ? new TurboHostHeader() : header;
        this.advertisingSettings = advertisingSettings == null ? Collections.emptyMap() : advertisingSettings;
        this.analyticsSettings = analyticsSettings == null ? Collections.emptyList() : analyticsSettings;
        this.accessSettings = accessSettings == null ? new TurboAccessSettings(null, null) : accessSettings;
        this.menuSettings = menuSettings == null ? Collections.emptyList() : menuSettings;
        this.feedbackSettings = feedbackSettings;
        this.css = css;
        this.minifiedCss = minifiedCss;
        this.autoRelated = ObjectUtils.firstNonNull(autoRelated, false);                            // false по умолчанию
        this.autoRelatedSettings = ObjectUtils.firstNonNull(autoRelatedSettings, TurboAutoRelatedSettings.getDefaultSettings());   // OFF по умолчанию
        this.commerceSettings = commerceSettings;
        // fallback на старый UserAgreement
        if (userAgreement == null && feedbackSettings != null) {
            // скопируем userAgreement из кнопки обратной связи при ее наличии
            userAgreement = feedbackSettings.findUserAgreement();
        }
        this.userAgreement = userAgreement;
        this.searchSettings = searchSettings;
        this.topMenuSettings = topMenuSettings == null ? Collections.emptyList() : topMenuSettings;
        this.authorizationSettings = authorizationSettings;
        this.commentsSettings = commentsSettings;
        this.autoMorda = ObjectUtils.firstNonNull(autoMorda, false);
        this.autoMenuSettings = autoMenuSettings == null ? Collections.emptyList() : autoMenuSettings;
        this.displaySettings = displaySettings;
    }

    @JsonIgnore
    public String getMinifiedCss() {
        return minifiedCss;
    }

    @JsonIgnore
    public String urlWithAuthentification(String url) throws URISyntaxException {
        if (accessSettings == null || Strings.isNullOrEmpty(accessSettings.getLogin()) ||
                Strings.isNullOrEmpty(accessSettings.getPassword())) {
            return url;
        }
        return new URIBuilder(url).setUserInfo(accessSettings.getLogin(), accessSettings.getPassword()).toString();
    }

    @JsonIgnore
    public List<AdvertisingSettings> getAdvertisingSettingsList() {
        return AdvertisingSettings.adsListFromMap(advertisingSettings);
    }

    public static TurboHostSettingsBuilder builder() {
        return new TurboHostSettingsBuilder();
    }

    @Getter
    @Setter
    public static final class TurboHostSettingsBuilder {

        private TurboHostHeader header;
        private Map<AdvertisingPlacement, List<AdvertisingSettings>> advertisingSettings;
        private Set<AdvertisingPlacement> changedAdvertisingPlacements = EnumSet.noneOf(AdvertisingPlacement.class);
        private List<AnalyticsSettings> analyticsSettings;
        private TurboAccessSettings accessSettings;
        private List<TurboMenuItem> menuSettings;
        private TurboFeedbackSettings feedbackSettings;
        private String css;
        private String minifiedCss;
        private Boolean autoRelated;
        private TurboAutoRelatedSettings autoRelatedSettings;
        private TurboCommerceSettings commerceSettings;
        private TurboUserAgreement userAgreement;
        private TurboSearchSettings searchSettings;
        private List<TurboMenuItem> topMenuSettings;
        private TurboAuthorizationSettings authorizationSettings;
        private TurboCommentsSettings commentsSettings;
        private Boolean autoMorda;
        private List<TurboMenuItem> autoMenuSettings;
        private TurboDisplaySettings displaySettings;

        public TurboHostSettingsBuilder() {
        }

        public TurboHostSettingsBuilder(TurboHostSettings settings) {
            if (settings != null) {
                this.header = settings.header;
                this.advertisingSettings = settings.advertisingSettings;
                this.analyticsSettings = settings.analyticsSettings;
                this.accessSettings = settings.accessSettings;
                this.menuSettings = settings.menuSettings;
                this.feedbackSettings = settings.feedbackSettings;
                this.css = settings.css;
                this.minifiedCss = settings.minifiedCss;
                this.autoRelated = settings.autoRelated;
                this.autoRelatedSettings = settings.autoRelatedSettings;
                this.commerceSettings = settings.commerceSettings;
                this.userAgreement = settings.userAgreement;
                this.searchSettings = settings.searchSettings;
                this.topMenuSettings = settings.topMenuSettings;
                this.authorizationSettings = settings.authorizationSettings;
                this.commentsSettings = settings.commentsSettings;
                this.autoMorda = settings.autoMorda;
                this.autoMenuSettings = settings.autoMenuSettings;
                this.displaySettings = settings.displaySettings;
            }
        }

        public TurboHostSettingsBuilder setHeader(TurboHostHeader header) {
            this.header = header;
            return this;
        }

        public TurboHostSettingsBuilder setAdvertisingSettings(List<AdvertisingSettings> advertisingSettings) {
            Map<AdvertisingPlacement, List<AdvertisingSettings>> newSettings = AdvertisingSettings.adsMapFromList(advertisingSettings);
            changedAdvertisingPlacements.addAll(AdvertisingSettings.getChangedPlacements(newSettings, this.advertisingSettings));
            this.advertisingSettings = newSettings;
            return this;
        }

        public TurboHostSettingsBuilder setAnalyticsSettings(List<AnalyticsSettings> analyticsSettings) {
            this.analyticsSettings = analyticsSettings;
            return this;
        }

        public TurboHostSettingsBuilder setAccessSettings(TurboAccessSettings accessSettings) {
            this.accessSettings = accessSettings;
            return this;
        }

        public TurboHostSettingsBuilder setMenuSettings(List<TurboMenuItem> menuSettings) {
            this.menuSettings = menuSettings;
            return this;
        }

        public TurboHostSettingsBuilder setFeedbackSettings(TurboFeedbackSettings feedbackSettings) {
            this.feedbackSettings = feedbackSettings;
            return this;
        }

        public TurboHostSettingsBuilder setCss(String css, String minifiedCss) {
            this.css = css;
            this.minifiedCss = minifiedCss;
            return this;
        }

        public TurboHostSettingsBuilder setAutoRelated(Boolean autoRelated) {
            this.autoRelated = autoRelated;
            return this;
        }

        public TurboHostSettingsBuilder setAutoRelatedSettings(TurboAutoRelatedSettings autoRelatedSettings) {
            this.autoRelatedSettings = autoRelatedSettings;
            return this;
        }

        public TurboHostSettingsBuilder setCommerceSettings(TurboCommerceSettings commerceSettings) {
            this.commerceSettings = commerceSettings;
            return this;
        }

        public TurboCommerceSettings getCommerceSettings() {
            return commerceSettings;
        }

        public TurboHostSettingsBuilder setUserAgreement(TurboUserAgreement userAgreement) {
            this.userAgreement = userAgreement;
            return this;
        }

        public TurboHostSettingsBuilder setSearchSettings(TurboSearchSettings searchSettings) {
            this.searchSettings = searchSettings;
            return this;
        }

        public TurboHostSettingsBuilder setTopMenuSettings(List<TurboMenuItem> topMenuSettings) {
            this.topMenuSettings = topMenuSettings;
            return this;
        }

        public TurboHostSettingsBuilder setAuthorizationSettings(TurboAuthorizationSettings authorizationSettings) {
            this.authorizationSettings = authorizationSettings;
            return this;
        }

        public TurboHostSettingsBuilder setCommentsSettings(TurboCommentsSettings commentsSettings) {
            this.commentsSettings = commentsSettings;
            return this;
        }

        public TurboHostSettingsBuilder setAutoMorda(Boolean autoMorda) {
            this.autoMorda = autoMorda;
            return this;
        }

        public TurboHostSettingsBuilder setAutoMenuSettings(List<TurboMenuItem> autoMenuSettings) {
            this.autoMenuSettings = autoMenuSettings;
            return this;
        }

        public TurboHostSettingsBuilder setDisplaySettings(TurboDisplaySettings displaySettings) {
            this.displaySettings = displaySettings;
            return this;
        }

        public TurboHostSettings build() {
            return new TurboHostSettings(header, advertisingSettings, analyticsSettings, accessSettings, menuSettings,
                    feedbackSettings, css, minifiedCss, autoRelated, autoRelatedSettings, commerceSettings, userAgreement,
                    searchSettings, topMenuSettings, authorizationSettings, commentsSettings, autoMorda, autoMenuSettings, displaySettings);
        }
    }
}
