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

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;

import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.turbo.model.TurboSource;
import ru.yandex.webmaster3.core.turbo.model.autoparser.AutoparserToggleState;
import ru.yandex.webmaster3.core.turbo.model.autoparser.TurboAutoparsedHostInfo;
import ru.yandex.webmaster3.core.turbo.model.feed.TurboFeedType;
import ru.yandex.webmaster3.core.turbo.model.statistics.TurboSearchUrlsStats;
import ru.yandex.webmaster3.core.util.WwwUtil;
import ru.yandex.webmaster3.storage.turbo.dao.TurboDomainSettingsYDao;
import ru.yandex.webmaster3.storage.turbo.dao.TurboDomainsStateCHDao;
import ru.yandex.webmaster3.storage.turbo.dao.automorda.TurboAutoMordaStatus;
import ru.yandex.webmaster3.storage.turbo.dao.autoparser.TurboAutoparsedYDao;
import ru.yandex.webmaster3.storage.turbo.dao.statistics.TurboSearchUrlsStatsCHDao;
import ru.yandex.webmaster3.storage.turbo.service.TurboDomainsStateService.TurboDomainState;

/**
 * ishalaru
 * 03.03.2020
 **/
@Component("turboSearchUrlsStatisticsService")
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class TurboSearchUrlsStatisticsService {
    private static final long PERMANENT_TURBO_SOURCE = ~(long)(TurboSource.AUTO_MORDA.value() | TurboSource.AUTOPARSER_BUTTON.value() | TurboSource.AUTOPARSER.value());
    private static final long AUTOPARSER_TURBO_SOURCE = TurboSource.AUTOPARSER_BUTTON.value() | TurboSource.AUTOPARSER.value();

    private final TurboAutoparsedYDao turboAutoparsedYDao;
    private final TurboDomainsStateCHDao turboDomainsStateCHDao;
    private final TurboSearchUrlsStatsCHDao turboSearchUrlsStatsCHDao;
    private final TurboDomainSettingsYDao turboDomainSettingsYDao;

    public long countTurboPages(TurboSourceStatuses turboSourceStatuses, Map<TurboSource, Long> map) {
        if (turboSourceStatuses == null) {
            return 0L;
        }
        long totalTurboPages = map.values().stream().mapToLong(Long::longValue).sum();
        if (!turboSourceStatuses.isAutoparser()) {
            totalTurboPages -= map.getOrDefault(TurboSource.AUTOPARSER, 0L);
            totalTurboPages -= map.getOrDefault(TurboSource.AUTOPARSER_BUTTON, 0L);
        }
        if (!turboSourceStatuses.isAutoMorda()) {
            totalTurboPages -= map.getOrDefault(TurboSource.AUTO_MORDA, 0L);
        }
        if (!turboSourceStatuses.isListingsEnabled()) {
            totalTurboPages -= map.getOrDefault(TurboSource.YML_LISTING, 0L);
        }
        return totalTurboPages;
    }

    private static final Map<TurboSource, Predicate<TurboSourceStatuses>> SOURCES_FILTER = ImmutableMap.of(
            TurboSource.AUTOPARSER, TurboSourceStatuses::isAutoparser,
            TurboSource.AUTOPARSER_BUTTON, TurboSourceStatuses::isAutoparser,
            TurboSource.AUTO_MORDA, TurboSourceStatuses::isAutoMorda,
            TurboSource.YML_LISTING, TurboSourceStatuses::isListingsEnabled
    );

    public long countTurboPages(TurboSourceStatuses turboSourceStatuses, Map<TurboSource, Long> map, boolean isYml) {
        long total = 0;
        for (Map.Entry<TurboSource, Long> entry : map.entrySet()) {
            TurboSource source = entry.getKey();
            if (source.isYml() == isYml && SOURCES_FILTER.getOrDefault(source, Predicates.alwaysTrue()).test(turboSourceStatuses)) {
                total += entry.getValue();
            }
        }
        return total;
    }

    public TurboSourceStatuses getTurboSourceStatuses(String domain) {
        return getTurboSourceStatuses(Collections.singleton(domain)).get(domain);
    }

    public Map<String, TurboSourceStatuses> getTurboSourceStatuses(Collection<String> domains) {
        Map<String, TurboSourceStatuses> result = new HashMap<>();
        Map<String, TurboDomainState> domainsState = turboDomainsStateCHDao.getDomainsStateOnlyFeedsAndAutomorda(domains);
        Map<String, TurboAutoparsedHostInfo> autoparserInfo = turboAutoparsedYDao.get(domains);
        Map<String, Boolean> autoMordaStatuses = turboDomainSettingsYDao.getAutoMordaStatuses(domains);

        for (String domain : domains) {
            TurboDomainState domainState = domainsState.get(domain);
            if (domainState == null) {
                domainState = TurboDomainState.empty(domain);
            }
            AutoparserToggleState toggleState = Optional.ofNullable(autoparserInfo.get(domain))
                    .map(TurboAutoparsedHostInfo::getCheckboxState).orElse(AutoparserToggleState.ABSENT);
            TurboAutoMordaStatus mordaStatus = domainState.getAutoMordaStatus();
            boolean mordaEnabled = autoMordaStatuses.getOrDefault(domain, false);
            boolean listingsEnabled = true; // listing ALWAYS enabled

            boolean hasActiveRssFeeds = domainState.getRssFeeds().stream().anyMatch(f -> f.isActive() && f.getType() == TurboFeedType.RSS);
            boolean hasActiveYmlFeeds = domainState.getYmlFeeds().stream().anyMatch(f -> f.isActive() && f.getType() == TurboFeedType.YML);
            result.put(domain, new TurboSourceStatuses(toggleState, mordaStatus, mordaEnabled, listingsEnabled, hasActiveRssFeeds, hasActiveYmlFeeds));
        }
        return result;
    }

    public TurboSourceStatuses getTurboSourceStatuses(WebmasterHostId hostId) {
        return getTurboSourceStatuses(WwwUtil.cutWWWAndM(hostId));
    }

    public long countTurboPages(String domain) {
        TurboSearchUrlsStats turboStats = turboSearchUrlsStatsCHDao.getStats(domain);
        return countTurboPages(getTurboSourceStatuses(domain), turboStats.getUrlsBySource());
    }

    public TurboDomainStats getTurboInfo(String domain) {
        return getTurboInfos(Collections.singleton(domain)).get(domain);
    }

    public Map<String, TurboDomainStats> getTurboInfos(Collection<String> domains) {
        Map<String, TurboSearchUrlsStats> searchStatsByDomain = turboSearchUrlsStatsCHDao.getStats(domains);
        Map<String, TurboSourceStatuses> turboSourceStatusesByDomain = getTurboSourceStatuses(domains);
        Map<String, TurboDomainStats> result = new HashMap<>();
        for (String domain : domains) {
            TurboSearchUrlsStats searchStats = searchStatsByDomain.getOrDefault(domain, TurboSearchUrlsStats.EMPTY);
            TurboSourceStatuses turboSourceStatuses = Objects.requireNonNull(turboSourceStatusesByDomain.get(domain));

            long turboSearchUrls = countTurboPages(turboSourceStatuses, searchStats.getUrlsBySource());
            long turboContentSearchUrls = countTurboPages(turboSourceStatuses, searchStats.getUrlsBySource(), false);
            long turboShopSearchUrls = countTurboPages(turboSourceStatuses, searchStats.getUrlsBySource(), true);
            TurboDomainStats stats = new TurboDomainStats.TurboDomainStatsBuilder()
                    .turboUrls(searchStats.getTurboUrls())
                    .turboSearchUrls(turboSearchUrls)
                    .turboContentSearchUrls(turboContentSearchUrls)
                    .turboShopSearchUrls(turboShopSearchUrls)
                    .autoparserToggleState(turboSourceStatuses.getAutoparserToggleState())
                    .hasActiveRssFeeds(turboSourceStatuses.isHasActiveRssFeeds())
                    .hasActiveYmlFeeds(turboSourceStatuses.isHasActiveYmlFeeds())
                    .build();
            result.put(domain, stats);
        }
        return result;
    }

    public static boolean isEnabledTurboPage(long turboSourceFlags, TurboSourceStatuses turboSourceStatuses) {
        //Если у страницы нет турбо источников (т.е. == 0), то сразу отправим false
        if (turboSourceFlags == 0) {
            return false;
        }
        //Если у страницы есть источники которые нельзья отключить то сразу да.
        if ((PERMANENT_TURBO_SOURCE & turboSourceFlags) != 0) {
            return true;
        }
        //Если это один из типов автопарсеров и автопарсер влючен, то это турбо страница.
        if ((AUTOPARSER_TURBO_SOURCE & turboSourceFlags) != 0 && turboSourceStatuses.isAutoparser()) {
            return true;
        }
        //Последний шанс, если это автоморда и она включена, то это турбо страница, в другом случае точно не турбо.
        return turboSourceStatuses.isAutoMorda() && (TurboSource.AUTO_MORDA.value() & turboSourceFlags) != 0;
    }

    @Value
    @Builder
    public static class TurboDomainStats {
        public static final TurboDomainStats EMPTY = new TurboDomainStatsBuilder().build();

        long turboUrls;
        long turboSearchUrls;
        long turboContentSearchUrls;
        long turboShopSearchUrls;
        AutoparserToggleState autoparserToggleState;
        boolean hasActiveRssFeeds;
        boolean hasActiveYmlFeeds;
    }

    @Value
    public static class TurboSourceStatuses {
        AutoparserToggleState autoparserToggleState;
        TurboAutoMordaStatus autoMordaStatus;
        boolean autoMordaEnabled;
        boolean listingsEnabled;
        boolean hasActiveRssFeeds;
        boolean hasActiveYmlFeeds;

        public boolean isAutoparser() {
            return autoparserToggleState == AutoparserToggleState.ON;
        }

        public boolean isAutoMorda() {
            return autoMordaStatus == TurboAutoMordaStatus.OK && autoMordaEnabled;
        }
    }

}
