package ru.yandex.webmaster3.worker.indexing;

import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Range;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import ru.yandex.webmaster3.core.WebmasterException;
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.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskState;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.core.worker.task.TaskResult;
import ru.yandex.webmaster3.storage.abt.AbtService;
import ru.yandex.webmaster3.storage.checklist.dao.ChecklistPageSamplesService;
import ru.yandex.webmaster3.storage.checklist.dao.ChecklistSamplesType;
import ru.yandex.webmaster3.storage.checklist.data.ProblemSignal;
import ru.yandex.webmaster3.storage.checklist.service.SiteProblemsService;
import ru.yandex.webmaster3.storage.util.yt.AsyncTableReader;
import ru.yandex.webmaster3.storage.util.yt.YtNode;
import ru.yandex.webmaster3.storage.util.yt.YtPath;
import ru.yandex.webmaster3.storage.util.yt.YtService;
import ru.yandex.webmaster3.storage.util.yt.YtTableReadDriver;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;

@Component("importDisallowedUrlsTask")
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ImportDisallowedUrlsTask extends PeriodicTask<ImportDisallowedUrlsTask.State> {

    private final SiteProblemsService siteProblemsService;
    private final YtService ytService;
    private final ChecklistPageSamplesService checklistPageSamplesService;
    private final AbtService abtService;
    @Value("${webmaster3.worker.indexing.importDisallowedUrls.ytDataDir}")
    private YtPath dataPath;

    @Override
    public Result run(UUID runId) throws Exception {
        log.info("Importing disallowed urls from {}", dataPath);
        DateTime updateStarted = DateTime.now();
        setState(new State());
        ytService.withoutTransaction(cypressService -> {
            YtNode ytNode = cypressService.getNode(dataPath);
            if (ytNode == null) {
                return false;
            }
            AsyncTableReader<DisallowedUrlsRow> reader = new AsyncTableReader<>(cypressService, ytNode.getPath(), Range.all(),
                    YtTableReadDriver.createYSONDriver(DisallowedUrlsRow.class)).withRetry(3).splitInParts(10000L);
            try (AsyncTableReader.TableIterator<DisallowedUrlsRow> iterator = reader.read()) {
                while (iterator.hasNext()) {
                    DisallowedUrlsRow row = iterator.next();
                    WebmasterHostId hostId = IdUtils.urlToHostId(row.getHost());
                    if (abtService.isInExperiment(hostId, "DISALLOWED_URLS_EXP")) {
                        List<String> list = row.getUrls().stream().map(x -> x.url).collect(Collectors.toList());
                        siteProblemsService.updateCleanableProblem(hostId, new ProblemSignal(new SiteProblemContent.DisallowedUrlsAlert(), DateTime.now()));
                        saveSamples(hostId, list);
                    }
                    state.hostsCnt++;
                }
            } catch (IOException e) {
                throw new WebmasterException("Yt IO error",
                        new WebmasterErrorResponse.YTServiceErrorResponse(getClass(), e), e);
            }
            siteProblemsService.notifyCleanableProblemUpdateFinished(SiteProblemTypeEnum.DISALLOWED_URLS_ALERT, updateStarted);
            return true;
        });

        return new Result(TaskResult.SUCCESS);
    }

    private void saveSamples(WebmasterHostId hostId, List<String> samples) {
        checklistPageSamplesService.saveSamples(hostId, ChecklistSamplesType.DISALLOWED_URLS_ALERT, samples);
    }

    @Override
    public PeriodicTaskType getType() {
        return PeriodicTaskType.IMPORT_DISALLOWED_URLS;
    }

    @Override
    public TaskSchedule getSchedule() {
        return TaskSchedule.startByCron("0 15 * * * *");
    }

    @lombok.Value
    private static class DisallowedUrlsRow {
        @JsonProperty("Host")
        String host;
        @JsonProperty("Urls")
        List<MeasuredUrl> urls;
    }

    @lombok.Value
    private static class MeasuredUrl {
        @JsonProperty("Clicks")
        Long clicks;
        @JsonProperty("Url")
        String url;
    }

    @Getter
    public class State implements PeriodicTaskState {
        int hostsCnt;
    }
}
