package ru.yandex.webmaster3.worker.turbo.commerce;

import com.google.common.collect.Range;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
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.TaskResult;
import ru.yandex.webmaster3.storage.util.ydb.exception.WebmasterYdbException;
import ru.yandex.webmaster3.storage.host.CommonDataState;
import ru.yandex.webmaster3.storage.host.CommonDataType;
import ru.yandex.webmaster3.storage.settings.SettingsService;
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 java.io.IOException;
import java.util.UUID;

/**
 * @author: ishalaru
 * DATE: 30.08.2019
 */
@Slf4j
public abstract class ImportTurboAutoRelatedTask<T> extends PeriodicTask<PeriodicTaskState> {
    @Autowired
    private SettingsService settingsService;
    @Autowired
    private YtService ytService;


    protected abstract YtPath getTablePath();

    protected abstract CommonDataType getCommonDataType();

    protected abstract Class<T> getRowType();

    protected abstract void processRow(T row, DateTime updateTime);

    protected void beforeExecution() {
        log.debug("Start processing data.");
    }

    protected void afterExecution() {
        log.debug("End processing data.");
    }

    @Override
    public Result run(UUID runId) throws Exception {
        beforeExecution();
        ytService.inTransaction(getTablePath()).execute(cypressService -> {
            YtNode node = cypressService.getNode(getTablePath());
            DateTime updateTime = node.getUpdateTime();
            CommonDataState prevUpdate = settingsService.getSettingUncached(getCommonDataType());
            if (prevUpdate != null && Long.parseLong(prevUpdate.getValue()) >= updateTime.getMillis()) {
                log.info("No new data found in table {}", getTablePath());
                return true;
            }
            AsyncTableReader<T> reader = new AsyncTableReader<>(cypressService, getTablePath(),
                    Range.all(), YtTableReadDriver.createYSONDriver(getRowType()))
                    .splitInParts(1000L);

            try (AsyncTableReader.TableIterator<T> iterator = reader.read()) {
                while (iterator.hasNext()) {
                    T row = iterator.next();
                    processRow(row, updateTime);
                }

            } catch (IOException e) {
                throw new WebmasterException("Yt error",
                        new WebmasterErrorResponse.YTServiceErrorResponse(getClass(), e), e);
            } catch (WebmasterYdbException e) {
                throw e.asUnchecked("Cassandra error", getClass());
            }
            settingsService.update(getCommonDataType(), String.valueOf(updateTime.getMillis()));
            return true;
        });
        afterExecution();
        return new Result(TaskResult.SUCCESS);
    }

}
