package ru.yandex.webmaster3.core.codes;

import org.apache.commons.lang3.tuple.Pair;
import ru.yandex.webmaster3.core.util.enums.IntEnum;
import ru.yandex.wmtools.common.util.http.YandexHttpStatus;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * User: azakharov
 * Date: 18.12.14
 * Time: 13:18
 */
public enum ErrorGroupEnum implements IntEnum, ICodeGroup {
    DISALLOWED_BY_USER(0,
            HttpCodeGroup.HTTP_400_BAD_REQUEST,
            HttpCodeGroup.HTTP_403_FORBIDDEN,
            HttpCodeGroup.HTTP_404_NOT_FOUND,
            HttpCodeGroup.HTTP_410_GONE,
            HttpCodeGroup.HTTP_GROUP_1003,
            HttpCodeGroup.HTTP_GROUP_2005,
            HttpCodeGroup.HTTP_GROUP_2025
    ),

    SITE_ERROR(1,
            HttpCodeGroup.HTTP_GROUP_5XX,
            HttpCodeGroup.HTTP_GROUP_1001,
            //HttpCodeGroup.HTTP_GROUP_1002,
            HttpCodeGroup.HTTP_GROUP_1004,
            HttpCodeGroup.HTTP_GROUP_1007,
            //HttpCodeGroup.HTTP_GROUP_1008,
            HttpCodeGroup.HTTP_GROUP_1006,
            HttpCodeGroup.HTTP_GROUP_1021,
            HttpCodeGroup.HTTP_GROUP_2005,
            //HttpCodeGroup.HTTP_GROUP_2006,
            HttpCodeGroup.HTTP_GROUP_2014
            //HttpCodeGroup.HTTP_GROUP_2020
    ),

    UNSUPPORTED_BY_ROBOT(2,
            HttpCodeGroup.HTTP_GROUP_1005,
            HttpCodeGroup.HTTP_GROUP_2007,
            //HttpCodeGroup.HTTP_GROUP_2010,
            //HttpCodeGroup.HTTP_GROUP_2011,
            HttpCodeGroup.HTTP_GROUP_2013
            //HttpCodeGroup.HTTP_GROUP_2016
    );

    private final int value;
    private final Set<Integer> codes = new HashSet<>();

    ErrorGroupEnum(int value, HttpCodeGroup... groups) {
        this.value = value;
        for (HttpCodeGroup g : groups) {
            this.codes.addAll(g.getCodesInternal());
        }
    }

    public int value() {
        return value;
    }

    @Override
    public boolean contains(Integer httpCode) {
        if (httpCode == null) {
            return false;
        }

        if (!LinkType.BROKEN.contains(httpCode)) {
            return false;
        }

        Optional<ErrorGroupEnum> res = get(httpCode);
        return res.isPresent() && this == res.get();
    }

    public boolean contains(HttpCodeGroup codeGroup) {
        if (codeGroup == null) {
            return false;
        }
        for (int code : codeGroup.getCodesInternal()) {
            if (!contains(code)) {
                return false;
            }
        }

        return true;
    }

    public static Optional<ErrorGroupEnum> get(Integer httpCode) {
        if (httpCode == null) {
            return Optional.empty();
        }

        for (ErrorGroupEnum e : ErrorGroupEnum.values()) {
            if (e.codes.contains(httpCode)) {
                return Optional.of(e);
            }
        }

        return Optional.empty();
    }

    public static ErrorGroupEnum getForced(Integer httpCode) {
        Optional<ErrorGroupEnum> e = get(httpCode);
        return e.orElse(SITE_ERROR);

    }

    public Set<Integer> getHttpCodes() {
        return Arrays.stream(YandexHttpStatus.values())
                .map(status -> Pair.of(status, HttpCodeGroup.get(status.getCode())))
                .filter(p -> contains(p.getRight()))
                .map(p -> p.getLeft().getCode())
                .collect(Collectors.toSet());
    }
}
