package ru.yandex.webmaster3.worker.news;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import com.fasterxml.jackson.annotation.JsonProperty;
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.Service;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskState;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.storage.host.CommonDataState;
import ru.yandex.webmaster3.storage.host.CommonDataType;
import ru.yandex.webmaster3.storage.news.MassMediaDictYDao;
import ru.yandex.webmaster3.storage.settings.dao.CommonDataStateYDao;
import ru.yandex.webmaster3.storage.util.yt.AsyncTableReader;
import ru.yandex.webmaster3.storage.util.yt.YtCypressService;
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;

/**
 * ishalaru
 * 17.11.2020
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class ImportMassMediaDictPeriodicTask extends PeriodicTask<ImportMassMediaDictPeriodicTask.State> {
    @Value("${external.yt.service.arnold}://home/news/webmaster/export/agencies/latest")
    private YtPath path;
    private final YtService ytService;
    private final CommonDataStateYDao commonDataStateYDao;
    private final MassMediaDictYDao massMediaDictYDao;

    @Override
    public Result run(UUID runId) throws Exception {
        setState(new State());
        final DateTime lastImportedDate = Optional.ofNullable(commonDataStateYDao.getValue(CommonDataType.LAST_MASS_MEDIA_DICT_IMPORT)).
                map(state -> DateTime.parse(state.getValue()))
                .orElse(DateTime.parse("2020-11-01"));
        ytService.inTransaction(path).execute(cypressService -> {
            if (cypressService.exists(path)) {
                final YtNode node = cypressService.getNode(path);
                if (!node.getUpdateTime().isAfter(lastImportedDate)) {
                    return false;
                }
                processTable(cypressService, path);
                commonDataStateYDao.update(new CommonDataState(CommonDataType.LAST_MASS_MEDIA_DICT_IMPORT, DateTime.now().toString(), DateTime.now()));
                return true;
            }
            return false;
        });

        return Result.SUCCESS;
    }

    private void processTable(YtCypressService cypressService, YtPath tablePath) {
        AsyncTableReader<YtRow> tableReader =
                new AsyncTableReader<>(cypressService, tablePath, Range.all(),
                        YtTableReadDriver
                                .createYSONDriver(YtRow.class))
                        .splitInParts(100000)
                        .withThreadName("import-mass-media-dict-reader");

        try (AsyncTableReader.TableIterator<YtRow> iterator = tableReader.read()) {
            List<YtRow> list = new ArrayList<>();
            while (iterator.hasNext()) {
                final YtRow next = iterator.next();
                massMediaDictYDao.upsert(next.getId(), next.name);
            }
        } catch (IOException | InterruptedException e) {
            throw new WebmasterException("YT error",
                    new WebmasterErrorResponse.YTServiceErrorResponse(getClass(), e), e);
        }
    }

    @lombok.Value
    public static final class YtRow {
        @JsonProperty("id")
        Long id;
        @JsonProperty("name")
        String name;
    }

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

    @Override
    public TaskSchedule getSchedule() {
        return TaskSchedule.never();
    }

    public class State implements PeriodicTaskState {
    }
}
