package ru.yandex.webmaster3.core.turbo.model.feed;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.collections4.CollectionUtils;
import org.joda.time.DateTime;
import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.turbo.TurboConstants;
import ru.yandex.webmaster3.core.turbo.model.TurboUrl;
import ru.yandex.webmaster3.core.turbo.model.error.TurboError;
import ru.yandex.webmaster3.core.turbo.model.error.TurboErrorType;
import ru.yandex.webmaster3.core.turbo.model.error.TurboRawError;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Актуальная информация по турбо-фиду (ошибки, примеры, статистика)
 * Created by Oleg Bazdyrev on 04/08/2017.
 */
public class TurboFeedStatistics implements TurboFeedStatisticsInfo {

    private static final double MAX_IGNORED_IMAGES_ERRORS_SHARE = 0.1;
    private static final int MAX_IGNORED_IMAGES_ERRORS_COUNT = 5;

    private final WebmasterHostId hostId;
    private final String url;
    private final Boolean active; // true - продакшн, false - превью, null - старое для совместимости
    private final TurboFeedType type;
    private final DateTime updateDate;
    private final DateTime downloadDate;
    private final List<TurboUrl> turboUrls;
    private final List<TurboError> errors;
    private final List<TurboRawError> rawErrors;
    private final TurboFeedItemStatistics stats;
    private final String hash;

    @JsonCreator
    public TurboFeedStatistics(WebmasterHostId hostId, TurboFeedType type, String url, Boolean active,
                               List<TurboUrl> turboUrls, DateTime updateDate, DateTime downloadDate,
                               List<TurboError> errors, List<TurboRawError> rawErrors,
                               TurboFeedItemStatistics stats, String hash) {
        this.hostId = hostId;
        this.type = type;
        this.url = url;
        this.active = active;
        this.turboUrls = turboUrls;
        this.updateDate = updateDate;
        this.downloadDate = downloadDate;
        this.errors = errors;
        this.rawErrors = rawErrors;
        this.stats = stats;
        this.hash = hash;
    }

    public TurboFeedStatistics(TurboFeedType type, String url, Boolean active,
                               List<TurboUrl> turboUrls, DateTime updateDate, DateTime downloadDate,
                               List<TurboRawError> rawErrors, TurboFeedItemStatistics stats, String hash) {
        this.hostId = null;
        this.type = type;
        this.url = url;
        this.active = active;
        this.turboUrls = turboUrls;
        this.updateDate = updateDate;
        this.downloadDate = downloadDate;
        this.errors = null;
        this.rawErrors = rawErrors;
        this.stats = stats;
        this.hash = hash;
    }

    public WebmasterHostId getHostId() {
        return hostId;
    }

    @Description("URL фида")
    public String getUrl() {
        return url;
    }

    @Description("Тип фида")
    public TurboFeedType getType() {
        return type;
    }

    public Boolean isActive() {
        return active;
    }

    @Description("Примеры распаршенных страниц")
    public List<TurboUrl> getTurboUrls() {
        return turboUrls;
    }

    @Description("Когда статистика обновилась последний раз")
    public DateTime getUpdateDate() {
        return updateDate;
    }

    @Description("Дата-время загрузки фида")
    public DateTime getDownloadDate() {
        return downloadDate;
    }

    @Deprecated
    @Description("Ошибки с примерами")
    public List<TurboError> getErrors() {
        return errors;
    }

    @Description("Исходные ошибки")
    public List<TurboRawError> getRawErrors() {
        return rawErrors;
    }

    @Description("Статистика по item-ам")
    public TurboFeedItemStatistics getStats() {
        return stats;
    }

    @Description("Отладочная инфорамция для логов")
    public String getHash() {
        return hash;
    }

    @JsonIgnore
    public TurboCrawlState getState() {
        // нет ни одного турбо-урла - ошибка
        if (CollectionUtils.isEmpty(turboUrls) && (stats == null || stats.getValid() == 0)) {
            return TurboCrawlState.ERROR;
        }
        // если есть ошибки - предупреждение
        if (!CollectionUtils.isEmpty(errors) || !hasAcceptableCountOfImageErrors()) {
            return TurboCrawlState.WARNING;
        }
        // иначе все ок
        return TurboCrawlState.OK;
    }

    private boolean hasAcceptableCountOfImageErrors() {
        if (rawErrors == null) {
            return true;
        }
        if (Boolean.FALSE.equals(active) || stats == null) {
            return rawErrors.isEmpty();
        }
        int imagesErrors = 0;
        Set<String> itemsWithImageErrors = new HashSet<>();
        for (TurboRawError rawError : rawErrors) {
            TurboErrorType errorType = TurboErrorType.fromCode(rawError.getCode());
            if (errorType == TurboErrorType.UNKNOWN) {
                // не генерируем алерт по тем ошибкам, которые сами не знаем
                continue;
            }
            if (errorType == TurboErrorType.IMAGES_FETCH_ERROR) {
                imagesErrors++;
                if (rawError.getParams() != null && rawError.getParams().has(TurboConstants.FIELD_ITEM_URL)) {
                    itemsWithImageErrors.add(rawError.getParams().get(TurboConstants.FIELD_ITEM_URL).asText());
                }
            } else {
                imagesErrors = Integer.MAX_VALUE;
                break;
            }
        }
        double imageErrorsShare = itemsWithImageErrors.size() / (double) stats.getTotal();
        return imagesErrors <= MAX_IGNORED_IMAGES_ERRORS_COUNT && imageErrorsShare <= MAX_IGNORED_IMAGES_ERRORS_SHARE;
    }

}
