package ru.yandex.webmaster3.streamer.feeds.mbi;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.protobuf.InvalidProtocolBufferException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.webmaster3.core.checklist.data.SiteProblemContent;
import ru.yandex.webmaster3.core.checklist.data.SiteProblemTypeEnum;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.logbroker.reader.IDataProcessing;
import ru.yandex.webmaster3.core.logbroker.reader.MessageContainer;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.util.TimeUtils;
import ru.yandex.webmaster3.core.util.json.JsonMapping;
import ru.yandex.webmaster3.proto.alerts.BadUrl;
import ru.yandex.webmaster3.storage.abt.AbtService;
import ru.yandex.webmaster3.storage.abt.model.Experiment;
import ru.yandex.webmaster3.storage.checklist.dao.ChecklistPageSamplesService;
import ru.yandex.webmaster3.storage.checklist.dao.ChecklistSamplesType;
import ru.yandex.webmaster3.storage.checklist.dao.HostsWithUrlAlertYDao;
import ru.yandex.webmaster3.storage.checklist.data.ProblemSignal;
import ru.yandex.webmaster3.storage.checklist.service.SiteProblemsService;
import ru.yandex.webmaster3.storage.host.AllVerifiedHostsCacheService;
import ru.yandex.webmaster3.storage.searchurl.samples.data.BadUrlSample;
import ru.yandex.webmaster3.storage.settings.SettingsService;

import static ru.yandex.webmaster3.storage.host.CommonDataType.THRESHOLD_BAD_URLS;

/**
 * Created by Oleg Bazdyrev on 01/09/2021.
 */
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class BrokenUrlsEventAlertProcessing implements IDataProcessing {

    private final SettingsService settingsService;
    private final AbtService abtService;
    private final HostsWithUrlAlertYDao hostsWithUrlAlertYDao;
    private final ChecklistPageSamplesService checklistPageSamplesService;
    private final SiteProblemsService siteProblemsService;
    private final AllVerifiedHostsCacheService allVerifiedHostsCacheService;

    private static final String BAD_CODE = "4xx";
    private static final String INTERNAL_ERROR = "5xx";
    private final static Set<String> ENABLED_PROBLEMS = Set.of(BAD_CODE, INTERNAL_ERROR);

    @Override
    public void process(MessageContainer messageContainer) {
        Map<WebmasterHostId, List<String>> preparedSamples4xx = new HashMap<>();
        Map<WebmasterHostId, List<String>> preparedSamples5xx = new HashMap<>();
        Map<WebmasterHostId, ProblemSignal> problems = new HashMap<>();

        long hourInterval = TimeUtils.toHourInterval(System.currentTimeMillis());

        for (byte[] rawMessage : messageContainer.getRawMessages()) {
            try {

                var result = BadUrl.
                        TBrokenHostSignalToWebmasterExport.parseFrom(rawMessage);
                if (!ENABLED_PROBLEMS.contains(result.getCause())) {
                    continue;
                }
                double badUrlShare = result.getUrls() * 1.0 / result.getTotalUrls();
                if (badUrlShare < Double.parseDouble(settingsService.getSettingCached(THRESHOLD_BAD_URLS).getValue())) {
                    continue;
                }
                WebmasterHostId hostId = IdUtils.urlToHostId(result.getHost());

                if (!abtService.isInHashExperiment(hostId, Experiment.URL_ALERT_4XX)
                        || !allVerifiedHostsCacheService.contains(hostId)
                        || result.getTopUrlsList().isEmpty()) {
                    continue;
                }

                log.info("bad_urls_share - {} host_id - {}", badUrlShare, hostId);

                List<String> samples = result.getTopUrlsList().stream()
                        .map(topUrl -> JsonMapping.writeValueAsString(new BadUrlSample(hostId, topUrl.getUrl(),
                                topUrl.getLastHttpCode(), topUrl.getLastUpdateTime())))
                        .toList();

                SiteProblemContent urlAlertContent;
                if (BAD_CODE.equals(result.getCause())) {
                    urlAlertContent = new SiteProblemContent.UrlAlert4xx(hourInterval);
                    preparedSamples4xx.put(hostId, samples);
                } else {
                    urlAlertContent = new SiteProblemContent.UrlAlert5xx(hourInterval);
                    preparedSamples5xx.put(hostId, samples);
                }
                ProblemSignal problem = new ProblemSignal(urlAlertContent, DateTime.now());
                problems.put(hostId, problem);
            } catch (InvalidProtocolBufferException e) {
                log.error("Bad protobuf message", e);
            }
            if (preparedSamples4xx.size() > 0) {
                hostsWithUrlAlertYDao.insert(preparedSamples4xx.keySet(), SiteProblemTypeEnum.URL_ALERT_4XX);
                checklistPageSamplesService.saveSamples(Map.of(ChecklistSamplesType.URL_ALERT_4XX, preparedSamples4xx));
            }

            if (preparedSamples5xx.size() > 0) {
                hostsWithUrlAlertYDao.insert(preparedSamples5xx.keySet(), SiteProblemTypeEnum.URL_ALERT_5XX);
                checklistPageSamplesService.saveSamples(Map.of(ChecklistSamplesType.URL_ALERT_5XX, preparedSamples5xx));
            }

            problems.forEach(siteProblemsService::updateRealTimeProblem);
        }

        messageContainer.commit();
    }
}
