package ru.yandex.webmaster3.worker.delurl;

import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ru.yandex.webmaster3.core.delurl.DelUrlRequest;
import ru.yandex.webmaster3.core.delurl.ProcessDelurlRequestTaskData;
import ru.yandex.webmaster3.core.solomon.HandleCommonMetricsService;
import ru.yandex.webmaster3.core.solomon.Indicators;
import ru.yandex.webmaster3.core.solomon.SolomonSensor;
import ru.yandex.webmaster3.core.worker.client.WorkerClient;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskState;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.core.worker.task.WorkerTaskPriority;
import ru.yandex.webmaster3.storage.abt.AbtService;
import ru.yandex.webmaster3.storage.delurl.DelUrlRequestsService;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import static org.joda.time.DateTimeConstants.SECONDS_PER_MINUTE;

/**
 * @author leonidrom
 */
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Component
@Slf4j
public class DelurlResendStaleRequestsPeriodicTask extends PeriodicTask<DelurlResendStaleRequestsPeriodicTask.TaskState> {
    private static final Duration RESEND_PERIOD = Duration.standardHours(3);

    private final DelUrlRequestsService delurlRequestsService;
    private final WorkerClient workerClient;
    private final AbtService abtService;
    private final HandleCommonMetricsService handleCommonMetricsService;

    @Override
    public Result run(UUID runId) throws Exception {
        DateTime now = DateTime.now();
        TaskState taskState = new TaskState();
        setState(taskState);

        DateTime staleBefore = now.minus(DelUrlRequest.STALE_REQUEST_AGE);
        DateTime resendBefore = now.minus(RESEND_PERIOD);
        List<DelUrlRequest> reqs = delurlRequestsService.list(staleBefore, resendBefore);

        List<DelUrlRequest> unprocessedReqs = reqs.stream()
                .filter(r -> abtService.isInExperiment(r.getHostId(), "DELURL_SAMOVAR")) // TMP: delete after exp is 100%
                .filter(r -> !r.getState().isFinal())
                .collect(Collectors.toList());

        log.info("Total unprocessed reqs: {}", unprocessedReqs.size());
        unprocessedReqs.forEach(r -> {
            log.info("Unprocessed: {}", r);
        });

        List<DelUrlRequest> resentReqs = unprocessedReqs.stream()
                .filter(r -> r.getUpdateDate().isBefore(resendBefore))
                .map(r-> r.withUpdateDate(now).withRetriesCount(r.getRetriesCount() + 1))
                .collect(Collectors.toList());

        log.info("Total reqs to resend: {}", resentReqs.size());
        resentReqs.forEach(r -> {
            log.info("Resend: {}", r);
        });

        if (!resentReqs.isEmpty()) {
            delurlRequestsService.updateBatch(resentReqs);
            resentReqs.stream()
                    .collect(Collectors.groupingBy(DelUrlRequest::getHostId, Collectors.toList())).
                    forEach((k, v) -> workerClient.enqueueTask(new ProcessDelurlRequestTaskData(k, WorkerTaskPriority.NORMAL, v)));
        }

        List<SolomonSensor> sensors = new ArrayList<>();
        sensors.add(SolomonSensor.createAligned(System.currentTimeMillis(), SECONDS_PER_MINUTE, resentReqs.size())
                .withLabel(SolomonSensor.LABEL_SECTION, "delurl")
                .withLabel(SolomonSensor.LABEL_INDICATOR, Indicators.COUNT)
                .withLabel(SolomonSensor.LABEL_DATA_TYPE, "resent_requests"));
        handleCommonMetricsService.handle(sensors, 1);

        taskState.reqsToRecrawl = resentReqs.size();
        taskState.unprocessedReqs = unprocessedReqs.size();

        return Result.SUCCESS;
    }

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

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

    @Data
    public static class TaskState implements PeriodicTaskState {
        public int reqsToRecrawl;
        public int unprocessedReqs;
    }
}
