package ru.yandex.webmaster3.storage.ytimport;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Preconditions;
import org.joda.time.Instant;
import org.joda.time.LocalDate;
import ru.yandex.webmaster3.storage.util.yt.YtPath;

import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * Состояние загрузки каких-либо данные из YT в Clickhouse
 * Created by Oleg Bazdyrev on 10/04/2017.
 */
public class YtClickhouseDataLoad {

    /**
     * Тип импорта
     */
    private final YtClickhouseDataLoadType type;
    /**
     * Текущее состояние загрузки
     */
    private final YtClickhouseDataLoadState state;
    /**
     * Период обновления данных
     */
    private final LocalDate dateFrom;
    private final LocalDate dateTo;
    /**
     * Произвольные данные выполнения
     */
    private final String data;
    /**
     * Момент последнего обновления статуса загрузки
     */
    private final Instant lastUpdated;
    /**
     * Момент последнего успешного завершения
     */
    private final Instant lastSuccess;
    /**
     * Исходная таблица с данными в YT
     */
    private final YtPath sourceTable;
    /**
     * Подготовленные для импорта таблицы в YT
     */
    private final List<YtPath> preparedTables;
    /**
     * Идентификаторы задач импорта {@link ru.yandex.webmaster3.storage.ytimport.YtClickhouseImportCommand}
     */
    private final List<UUID> importTaskIds;
    /**
     * Идентификаторы задач репликации {@link ru.yandex.webmaster3.storage.clickhouse.replication.data.ClickhouseReplicationCommand}
     */
    private final List<UUID> replicationTaskIds;

    public YtClickhouseDataLoad(YtClickhouseDataLoadType type, YtClickhouseDataLoadState state, LocalDate dateFrom,
                                LocalDate dateTo, Instant lastUpdated, YtPath sourceTable,
                                List<YtPath> preparedTables, List<UUID> importTaskIds, List<UUID> replicationTaskIds) {
        this(type, state, dateFrom, dateTo, lastUpdated, null, null, sourceTable, preparedTables, importTaskIds, replicationTaskIds);
    }

    public YtClickhouseDataLoad(YtClickhouseDataLoadType type, YtClickhouseDataLoadState state, LocalDate dateFrom,
                                LocalDate dateTo, Instant lastUpdated, Instant lastSuccess, String data, YtPath sourceTable,
                                List<YtPath> preparedTables, List<UUID> importTaskIds, List<UUID> replicationTaskIds) {
        this.type = type;
        this.state = state;
        this.dateFrom = dateFrom;
        this.dateTo = dateTo;
        this.lastUpdated = lastUpdated == null ? Instant.now() : lastUpdated;
        this.lastSuccess = lastSuccess;
        this.data = data;
        this.sourceTable = sourceTable;
        this.preparedTables = preparedTables;
        this.importTaskIds = importTaskIds;
        this.replicationTaskIds = replicationTaskIds;
    }

    /**
     * Создает пустую запись (т.е. никакой загрузки еще не выполнялось)
     */
    public static YtClickhouseDataLoad createDefault(YtClickhouseDataLoadType type) {
        return new YtClickhouseDataLoad(type, YtClickhouseDataLoadState.INITIALIZING, null, null, null, null, null, null,  null, null, null);
    }

    /**
     * Устанавливает информацию об источнике данных
     */
    public YtClickhouseDataLoad withSourceTable(YtPath sourceTable, LocalDate dateFrom, LocalDate dateTo) {
        return new YtClickhouseDataLoad(type, YtClickhouseDataLoadState.PREPARING, dateFrom, dateTo, null, lastSuccess,
                data, sourceTable,  preparedTables, importTaskIds, replicationTaskIds);
    }

    /**
     * Устанавливает новый статус загруки
     */
    public YtClickhouseDataLoad withState(YtClickhouseDataLoadState state) {
        if (this.state != YtClickhouseDataLoadState.FAILED) {
            return new YtClickhouseDataLoad(type, state, dateFrom, dateTo, null, lastSuccess,
                    data, sourceTable,  preparedTables, importTaskIds, replicationTaskIds);
        } else {
            return this;
        }
    }

    public YtClickhouseDataLoad withLastSuccess(Instant lastSuccess) {
        return new YtClickhouseDataLoad(type, state, dateFrom, dateTo, null, lastSuccess,
                data, sourceTable,  preparedTables, importTaskIds, replicationTaskIds);
    }

    /**
     * Устанавливает следующий статус
     */
    public YtClickhouseDataLoad withNextState() {
        Preconditions.checkState(!this.state.isTerminal());
        return new YtClickhouseDataLoad(type, YtClickhouseDataLoadState.values()[state.ordinal() + 1], dateFrom, dateTo,
                null, lastSuccess, data, sourceTable,  preparedTables, importTaskIds, replicationTaskIds);
    }

    /**
     * Устанавливает промежуточные таблицы в YT
     */
    public YtClickhouseDataLoad withPreparedTables(List<YtPath> preparedTables) {
        return new YtClickhouseDataLoad(type, state, dateFrom, dateTo, null, lastSuccess,
                data, sourceTable,  preparedTables, importTaskIds, replicationTaskIds);
    }

    public YtClickhouseDataLoad withImportTaskIds(UUID... importTaskIds) {
        return new YtClickhouseDataLoad(type, state, dateFrom, dateTo, null, lastSuccess,
                data, sourceTable,  preparedTables, Arrays.asList(importTaskIds), replicationTaskIds);
    }

    public YtClickhouseDataLoad withReplicationTaskIds(UUID... replicationTaskIds) {
        return new YtClickhouseDataLoad(type, state, dateFrom, dateTo, null, lastSuccess,
                data, sourceTable,  preparedTables, importTaskIds, Arrays.asList(replicationTaskIds));
    }

    public YtClickhouseDataLoad withData(String data) {
        return new YtClickhouseDataLoad(type, state, dateFrom, dateTo, null, lastSuccess,
                data, sourceTable,  preparedTables, importTaskIds, replicationTaskIds);
    }

    public YtClickhouseDataLoad restarted() {
        return new YtClickhouseDataLoad(type, YtClickhouseDataLoadState.PREPARING, dateFrom, dateTo, null, lastSuccess,
                data, sourceTable,  preparedTables, importTaskIds, replicationTaskIds);
    }

    public YtClickhouseDataLoadType getType() {
        return type;
    }

    public YtClickhouseDataLoadState getState() {
        return state;
    }

    public LocalDate getDateFrom() {
        return dateFrom;
    }

    public LocalDate getDateTo() {
        return dateTo;
    }

    public String getData() {
        return data;
    }

    public Instant getLastUpdated() {
        return lastUpdated;
    }

    public Instant getLastSuccess() {
        return lastSuccess;
    }

    public YtPath getSourceTable() {
        return sourceTable;
    }

    public List<YtPath> getPreparedTables() {
        return preparedTables;
    }

    public List<UUID> getImportTaskIds() {
        return importTaskIds;
    }

    public List<UUID> getReplicationTaskIds() {
        return replicationTaskIds;
    }

    @JsonIgnore
    public LocalDate getMaxProcessedDate() {
        return state == YtClickhouseDataLoadState.DONE ? dateTo : dateFrom.minusDays(1);
    }

    @Override
    public String toString() {
        return "YtClickhouseDataLoad{" +
                "type=" + type +
                ", state=" + state +
                ", dateFrom=" + dateFrom +
                ", dateTo=" + dateTo +
                ", data='" + data + '\'' +
                ", lastUpdated=" + lastUpdated +
                ", sourceTable=" + sourceTable +
                ", preparedTables=" + preparedTables +
                ", importTaskIds=" + importTaskIds +
                ", replicationTaskIds=" + replicationTaskIds +
                '}';
    }
}
