package ru.yandex.webmaster3.storage.turbo.dao;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.core.turbo.model.TurboAccessSettings;
import ru.yandex.webmaster3.core.turbo.model.TurboAutoRelatedSettings;
import ru.yandex.webmaster3.core.turbo.model.TurboDisplaySettings;
import ru.yandex.webmaster3.core.turbo.model.TurboHostHeader;
import ru.yandex.webmaster3.core.turbo.model.TurboHostSettings;
import ru.yandex.webmaster3.core.turbo.model.TurboUserAgreement;
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.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.TurboMenuItem;
import ru.yandex.webmaster3.core.turbo.model.search.TurboSearchSettings;
import ru.yandex.webmaster3.core.util.W3Collectors;
import ru.yandex.webmaster3.storage.util.ydb.AbstractYDao;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.DataMapper;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Field;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Fields;


/**
 * Created by Oleg Bazdyrev on 14/06/2018.
 * DAO для настроек доменов-турбо
 */
@Repository
public class TurboDomainSettingsYDao extends AbstractYDao {

    public static final String TABLE_NAME = "turbo_domain_settings";
    private static final DataMapper<TurboHostSettings> SETTINGS_MAPPER = DataMapper.create(
            F.HEADER, F.ADVERTISING, F.ANALYTICS, F.ACCESS, F.MENU, F.FEEDBACK, F.CSS, F.MINIFIED_CSS, F.AUTO_RELATED, F.AUTO_RELATED_SETTINGS,
            F.COMMERCE, F.USER_AGREEMENT, F.SEARCH, F.TOP_MENU, F.AUTHORIZATION, F.COMMENTS, F.AUTO_MORDA, F.AUTO_MENU, F.DISPLAY,
            TurboHostSettings::new);
    private static final DataMapper<Pair<String, TurboHostSettings>> PAIR_MAPPER = DataMapper.create(
            F.DOMAIN, SETTINGS_MAPPER, Pair::of);
    private static final DataMapper<Pair<String, Boolean>> AUTO_MORDA_PAIR_MAPPER = DataMapper.create(
            F.DOMAIN, F.AUTO_MORDA, Pair::of);

    public TurboDomainSettingsYDao() {
        super(PREFIX_TURBO, TABLE_NAME);
    }

    public void updateSettings(String domain, TurboHostSettings settings) {
        upsert(F.DOMAIN.value(domain),
                F.HEADER.value(settings.getHeader()),
                F.ADVERTISING.value(settings.getAdvertisingSettings()),
                F.ANALYTICS.value(settings.getAnalyticsSettings()),
                F.ACCESS.value(settings.getAccessSettings()),
                F.MENU.value(settings.getMenuSettings()),
                F.FEEDBACK.value(settings.getFeedbackSettings()),
                F.CSS.value(settings.getCss()),
                F.MINIFIED_CSS.value(settings.getMinifiedCss()),
                F.AUTO_RELATED.value(settings.getAutoRelated()),
                F.AUTO_RELATED_SETTINGS.value(settings.getAutoRelatedSettings()),
                F.COMMERCE.value(settings.getCommerceSettings()),
                F.USER_AGREEMENT.value(settings.getUserAgreement()),
                F.SEARCH.value(settings.getSearchSettings()),
                F.TOP_MENU.value(settings.getTopMenuSettings()),
                F.AUTHORIZATION.value(settings.getAuthorizationSettings()),
                F.COMMENTS.value(settings.getCommentsSettings()),
                F.AUTO_MORDA.value(settings.getAutoMorda()),
                F.AUTO_MENU.value(settings.getAutoMenuSettings()),
                F.DISPLAY.value(settings.getDisplaySettings()))
                .execute();
    }

    public TurboHostSettings getSettings(String domain) {
        return select(SETTINGS_MAPPER).where(F.DOMAIN.eq(domain)).queryOne();
    }

    public Map<String, Boolean> getAutoMordaStatuses(Collection<String> domains) {
        if (domains.isEmpty()) {
            return Collections.emptyMap();
        }
        return select(AUTO_MORDA_PAIR_MAPPER).where(F.DOMAIN.in(domains)).queryForList().stream().filter(p -> p != null && p.getRight() != null)
                .collect(W3Collectors.toHashMap());
    }

    public void forEach(Consumer<Pair<String, TurboHostSettings>> consumer) {
        streamReader(PAIR_MAPPER, consumer);
    }

    private interface F {
        Field<String> DOMAIN = Fields.stringField("domain");
        Field<TurboHostHeader> HEADER = Fields.jsonField2("header", TurboHostHeader.class);
        Field<Map<AdvertisingPlacement, List<AdvertisingSettings>>> ADVERTISING = Fields.jsonField2("advertising", AdvertisingSettings.MAP_REFERENCE);
        Field<List<AnalyticsSettings>> ANALYTICS = Fields.jsonField2("analytics", AnalyticsSettings.LIST_REFERENCE);
        Field<TurboAccessSettings> ACCESS = Fields.jsonField2("access", TurboAccessSettings.class);
        Field<List<TurboMenuItem>> MENU = Fields.jsonField2("menu", TurboMenuItem.LIST_REFERENCE);
        Field<TurboFeedbackSettings> FEEDBACK = Fields.jsonField2("feedback", TurboFeedbackSettings.class).makeOptional();
        Field<String> CSS = Fields.stringField("css").makeOptional();
        Field<String> MINIFIED_CSS = Fields.stringField("minified_css").makeOptional();
        Field<Boolean> AUTO_RELATED = Fields.boolField("auto_related");
        Field<TurboAutoRelatedSettings> AUTO_RELATED_SETTINGS = Fields.jsonField2("auto_related_settings", TurboAutoRelatedSettings.class);
        Field<TurboCommerceSettings> COMMERCE = Fields.jsonField2("ecommerce", TurboCommerceSettings.class).makeOptional();
        Field<TurboUserAgreement> USER_AGREEMENT = Fields.jsonField2("user_agreement", TurboUserAgreement.class).makeOptional();
        Field<TurboSearchSettings> SEARCH = Fields.jsonField2("search", TurboSearchSettings.class).makeOptional();
        Field<List<TurboMenuItem>> TOP_MENU = Fields.jsonField2("top_menu", TurboMenuItem.LIST_REFERENCE);
        Field<TurboAuthorizationSettings> AUTHORIZATION = Fields.jsonField2("authorization", TurboAuthorizationSettings.class).makeOptional();
        Field<TurboCommentsSettings> COMMENTS = Fields.jsonField2("comments", TurboCommentsSettings.class).makeOptional();
        Field<Boolean> AUTO_MORDA = Fields.boolField("auto_morda");
        Field<List<TurboMenuItem>> AUTO_MENU = Fields.jsonField2("auto_menu", TurboMenuItem.LIST_REFERENCE);
        Field<TurboDisplaySettings> DISPLAY = Fields.jsonField2("display", TurboDisplaySettings.class).makeOptional();
    }
}
