package ru.yandex.webmaster3.storage.importer.model.init;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import ru.yandex.webmaster3.storage.importer.model.ImportContext;
import ru.yandex.webmaster3.storage.importer.model.ImportStage;
import ru.yandex.webmaster3.storage.importer.model.ImportTask;
import ru.yandex.webmaster3.storage.util.yt.YtPath;

/**
 * Created by Oleg Bazdyrev on 01/10/2020.
 */
@Slf4j
@Value
@AllArgsConstructor(onConstructor_ = @JsonCreator)
@Builder
@JsonIgnoreProperties(ignoreUnknown = true)
public class ImportInitByDateInName implements ImportInitPolicy {

    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormat.forPattern("yyyyMMdd");

    YtPath sourceDir;
    String tableNamePattern;
    String dateFormat;
    boolean failOnGap;

    @Override
    public ImportInitType getType() {
        return ImportInitType.BY_DATE_IN_NAME;
    }

    @Override
    public String getCluster() {
        return sourceDir.getCluster();
    }

    @Override
    public ImportTask apply(ImportContext context) {
        ImportTask task = context.getTask();
        Pattern pattern = Pattern.compile(tableNamePattern);
        // поищем в папке groupDir первый необработанный файл с данными
        List<YtPath> tables = context.getCypressService().list(sourceDir);
        tables.sort(YtPath::compareTo);
        // ищем первую таблицу с названием, большим текущей data
        LocalDate date = task.getPrevData(ImportStage.INIT, Data.class).map(Data::getDate).orElse(null);
        for (YtPath table : tables) {
            Matcher matcher = pattern.matcher(table.getName());
            if (!matcher.matches()) {
                continue;
            }
            LocalDate newDate = DateTimeFormat.forPattern(dateFormat).parseLocalDate(matcher.group(1));
            if (date == null || newDate.isAfter(date)) {
                log.info("Found new table for processing: " + table);
                if (date != null && failOnGap && !newDate.minusDays(1).equals(date)) {
                    String message = String.format("Found gap in tables. Prev date is %s, but new is %s", date, newDate);
                    log.error(message);
                    return task.updateError(message).build();
                }
                return task.withNextStage()
                        .started(DateTime.now())
                        .data(task.putData(ImportStage.INIT, new Data(newDate)))
                        .sourceTable(table).build();
            }
        }
        // ничего не нашли, сразу завершимся
        log.info("Expected table not found, nothing to import");
        return task.updateStage(ImportStage.DONE).build();
    }

    @Value
    @AllArgsConstructor(onConstructor_ = @JsonCreator)
    private static final class Data {
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
        LocalDate date;
    }

    @Override
    public LocalDate getImportedDate(Map<ImportStage, JsonNode> data) {
        return ImportTask.getData(data, ImportStage.INIT, Data.class).map(Data::getDate).orElse(null);
    }

}
