package ru.yandex.webmaster3.coordinator.http.host;

import com.google.common.collect.Range;
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.coordinator.http.SimpleRequest;
import ru.yandex.webmaster3.coordinator.http.SimpleResponse;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.http.Action;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.http.WriteAction;
import ru.yandex.webmaster3.storage.host.moderation.regions.HostRegionsModerationRequest;
import ru.yandex.webmaster3.storage.host.moderation.regions.HostRegionsModerationRequestStatus;
import ru.yandex.webmaster3.storage.host.moderation.regions.HostRegionsModerationYtResult;
import ru.yandex.webmaster3.storage.host.moderation.regions.dao.HostRegionsModerationRequestsYDao;
import ru.yandex.webmaster3.storage.host.moderation.regions.service.HostRegionsModerationYtService;
import ru.yandex.webmaster3.storage.util.yt.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author leonidrom
 */
@Slf4j
@WriteAction
@Component("/tmp/host/reimportHostRegionsModerationResults")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ReimportHostRegionsModerationResultsAction  extends Action<SimpleRequest, SimpleResponse> {
    private static final DateTime DATE_FROM = new DateTime("2021-04-30T00:00:00.000+03:00");

    private final HostRegionsModerationYtService hostRegionsModerationYtService;
    private final YtService ytService;
    private final HostRegionsModerationRequestsYDao hostRegionsModerationRequestsYDao;

    @Value("${external.yt.service.hahn.root.default}/import/yang/host_regions/archive/merged_moderation_results")
    private YtPath tablePath;

    @Override
    public SimpleResponse process(SimpleRequest request) throws WebmasterException {
        processYtResultTable(tablePath);
        return new SimpleResponse();
    }

    private int processYtResultTable(YtPath tablePath) {
        log.info("Processing results from {}", tablePath);

        Map<WebmasterHostId, HostRegionsModerationRequest> reqsCache = new HashMap<>();
        List<HostRegionsModerationYtResult> rows = new ArrayList<>();
        try {
            ytService.withoutTransaction(cypressService -> {
                readYtResultTable(cypressService, tablePath, rows);
                return true;
            });

            if (rows.isEmpty()) {
                throw new WebmasterException("Failed to read Yt result table (no data)",
                        new WebmasterErrorResponse.DataConsistencyErrorResponse(getClass(), "No data in Yt result table"));
            }
        } catch (YtException | InterruptedException e) {
            throw new WebmasterException("Failed to read YT results table",
                    new WebmasterErrorResponse.YTServiceErrorResponse(getClass(), e), e);
        }

        int cnt = 0;
        for (var row : rows) {
            if (cnt % 1000 == 0) {
                log.info("Processed: {}", cnt);
            }

            if (row.getModerationDate().isBefore(DATE_FROM)) {
                cnt++;
                continue;
            }

            WebmasterHostId rowHostId = row.getHostId();
            var req = reqsCache.getOrDefault(rowHostId, null);
            if (req == null) {
                req = hostRegionsModerationRequestsYDao.getLastRecord(rowHostId);
                reqsCache.put(rowHostId, req);
            }

            if (!req.getRequestId().equals(row.getRequestId())) {
                cnt++;
                continue;
            }

            if (req.getStatus() != HostRegionsModerationRequestStatus.IN_MODERATION) {
                cnt++;
                continue;
            }

            cnt++;
            log.info("Will import req: {}", req);
            // hostDisplayNameModerationYtService.processYtResult(row);
        }

        return rows.size();
    }

    private void readYtResultTable(YtCypressService cypressService, YtPath tablePath, List<HostRegionsModerationYtResult> outRows) throws YtException {
        var tableReadDriver = YtTableReadDriver.createYSONDriver(HostRegionsModerationYtResult.class);
        var tableReader = new AsyncTableReader<>(cypressService, tablePath, Range.all(), tableReadDriver)
                .withRetry(5);

        try (var it = tableReader.read()) {
            while (it.hasNext()) {
                outRows.add(it.next());
            }
        } catch (IOException | InterruptedException e) {
            throw new YtException("Unable to read table: " + tablePath, e);
        }
    }
}
