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

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import com.google.common.base.Suppliers;
import lombok.Builder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.data.WebmasterHostId.Schema;
import ru.yandex.webmaster3.core.host.service.HostOwnerService;
import ru.yandex.webmaster3.core.turbo.TurboConstants;
import ru.yandex.webmaster3.core.turbo.model.autoparser.TurboAutoparsedHostInfo;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.util.WwwUtil;
import ru.yandex.webmaster3.storage.host.service.CommercialOwnersService;
import ru.yandex.webmaster3.storage.turbo.dao.autoparser.TurboAutoparsedHostsSpeedsYDao;
import ru.yandex.webmaster3.storage.turbo.dao.autoparser.TurboAutoparsedHostsSpeedsYDao.OwnerSpeedInfo;
import ru.yandex.webmaster3.storage.turbo.dao.autoparser.TurboAutoparsedYDao;
import ru.yandex.webmaster3.storage.turbo.dao.autoparser.TurboAutoparserScreenshotsYDao;
import ru.yandex.webmaster3.storage.turbo.dao.autoparser.TurboRivalsScreenshotsYDao;
import ru.yandex.webmaster3.storage.turbo.dao.autoparser.TurboRivalsScreenshotsYDao.PageWithScreenshots;
import ru.yandex.webmaster3.storage.turbo.service.autoparser.TurboAutoparserInfoService;

/**
 * Created by Oleg Bazdyrev on 2019-08-21.
 */
@Service("turboSpeedLandingService")
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class TurboSpeedLandingService {

    private static final Double TURBO_SPEED = 800.0;

    private final Supplier<Map<Boolean, List<PageWithScreenshots>>> rivalsCache =
            Suppliers.memoizeWithExpiration(this::getRivalsScreenshotsMap, 300, TimeUnit.SECONDS);

    private final CommercialOwnersService commercialOwnersService;
    private final TurboAutoparsedHostsSpeedsYDao turboAutoparsedHostsSpeedsYDao;
    private final TurboAutoparserInfoService turboAutoparserInfoService;
    private final TurboAutoparserScreenshotsYDao turboAutoparserScreenshotsYDao;
    private final TurboRivalsScreenshotsYDao turboRivalsScreenshotsYDao;
    private final HostOwnerService hostOwnerService;
    private final TurboSearchUrlsStatisticsService turboSearchUrlsStatisticsService;
    private final TurboAutoparsedYDao turboAutoparsedYDao;

    public TurboSpeedLandingInfo findSpeedLandingInfo(String domain) {
        TurboAutoparsedHostInfo autoparserInfo = turboAutoparsedYDao.get(domain);
        TurboSpeedLandingInfo result = null;
        if (turboAutoparserInfoService.isHostInfoActual(autoparserInfo)) {
            result = findAutoparserSpeedLandingInfo(autoparserInfo);
            if (result != null) {
                return result;
            }
        }
        // fallback to rivals
        String owner = hostOwnerService.getHostOwner(domain);
        boolean isCommercial = commercialOwnersService.isCommercialOwner(IdUtils.urlToHostId(owner));
        // take from cache
        List<PageWithScreenshots> pages = rivalsCache.get().get(isCommercial);
        if (pages == null) {
            return null;
        }
        // get random rival
        Collections.shuffle(pages);
        for (PageWithScreenshots page : pages) {
            // check for turbo
            String rivalDomain = WwwUtil.cutWWWAndM(IdUtils.urlToHostId(page.getUrl()));

            // check for turbo on search
            if (turboSearchUrlsStatisticsService.countTurboPages(rivalDomain) <= 0) {
                continue;
            }
            OwnerSpeedInfo speedInfo = turboAutoparsedHostsSpeedsYDao.getSpeed(hostOwnerService.getHostOwner(rivalDomain));
            if (speedInfo == null || speedInfo.getNonTurboSpeed() == null) {
                continue;
            }
            TurboSpeedLandingSample screenshotSample = TurboSpeedLandingSample.builder()
                    .originalUrl(page.getUrl())
                    .originalScreenshotUrl(fixScreenshots(page.getScreenshot()))
                    .turboUrl(page.getTurboUrl())
                    .turboScreenshotUrl(fixScreenshots(page.getTurboScreenshot()))
                    .build();

            return TurboSpeedLandingInfo.builder()
                    .domain(rivalDomain)
                    .sourceDomain(domain)
                    .nonTurboSpeed(speedInfo.getNonTurboSpeed())
                    .turboSpeed(TURBO_SPEED)
                    .isCommercial(isCommercial)
                    .samples(Collections.singletonList(screenshotSample))
                    .build();
        }
        return null;
    }

    private Map<Boolean, List<PageWithScreenshots>> getRivalsScreenshotsMap() {
        return turboRivalsScreenshotsYDao.listAll().stream()
                .collect(Collectors.groupingBy(PageWithScreenshots::isCommercial));
    }

    private TurboSpeedLandingInfo findAutoparserSpeedLandingInfo(TurboAutoparsedHostInfo autoparserInfo) {
        // ищем инфу по скорости
        String domain = autoparserInfo.getHost();
        String owner = hostOwnerService.getHostOwner(domain);
        boolean isCommercial = commercialOwnersService.isCommercialOwner(IdUtils.urlToHostId(owner));
        OwnerSpeedInfo speedInfo = turboAutoparsedHostsSpeedsYDao.getSpeed(owner);
        if (speedInfo == null || speedInfo.getNonTurboSpeed() == null) {
            return null;
        }
        // search for first sample with screenshots
        Collections.shuffle(autoparserInfo.getSamples());
        for (var sample : autoparserInfo.getSamples()) {
            String screenshot = turboAutoparserScreenshotsYDao.getScreenshot(sample.getOriginUrl());
            String turboScreenshot = turboAutoparserScreenshotsYDao.getScreenshot(sample.getTurboUrl() + TurboConstants.NO_REDIRECT_PARAM);
            if (screenshot != null && turboScreenshot != null) {
                TurboSpeedLandingSample screenshotSample = TurboSpeedLandingSample.builder()
                        .originalUrl(sample.getOriginUrl())
                        .originalScreenshotUrl(fixScreenshots(screenshot))
                        .turboUrl(sample.getTurboUrl())
                        .turboScreenshotUrl(fixScreenshots(turboScreenshot))
                        .build();

                return TurboSpeedLandingInfo.builder()
                        .domain(domain)
                        .sourceDomain(domain)
                        .nonTurboSpeed(speedInfo.getNonTurboSpeed())
                        .turboSpeed(TURBO_SPEED)
                        .isCommercial(isCommercial)
                        .samples(Collections.singletonList(screenshotSample))
                        .build();
            }
        }
        return null;
    }

    private static String fixScreenshots(String screenshot) {
        return screenshot.replaceFirst(Schema.HTTP.getSchemaPrefix(), Schema.HTTPS.getSchemaPrefix());
    }

    @Builder
    @Getter
    public static class TurboSpeedLandingInfo {
        @Description("Домен, для которого приводится скорость и сравнение")
        private final String domain;
        private final String sourceDomain;
        private final boolean isCommercial;
        private final Double nonTurboSpeed;
        private final Double turboSpeed;
        private final List<TurboSpeedLandingSample> samples;
    }

    @Builder
    @Getter
    public static final class TurboSpeedLandingSample {
        @Description("Адрес исходной страницы")
        private final String originalUrl;
        @Description("Скриншот исходной страницы")
        private final String originalScreenshotUrl;
        @Description("Адрес автопаршенной турбо-версии")
        private final String turboUrl;
        @Description("Скриншот автопаршенной турбо-версии")
        private final String turboScreenshotUrl;
    }
}
