package ru.yandex.webmaster3.storage.achievements.model;

import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.ToString;
import org.jetbrains.annotations.NotNull;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.util.json.polymorphic.Polymorphic;
import ru.yandex.webmaster3.storage.achievements.model.official.AchievementOfficialType;
import ru.yandex.webmaster3.storage.achievements.model.official.OfficialInfo;

/**
 * Created by Oleg Bazdyrev on 17/08/2018.
 */
@ToString
public abstract class AchievementInfo implements Polymorphic<AchievementType>, Comparable<AchievementInfo> {

    private final AchievementType type;
    private final AchievementValueType valueType;

    AchievementInfo(AchievementType type, AchievementValueType valueType) {
        this.type = type;
        this.valueType = valueType;
    }

    @Override
    @JsonProperty("type")
    public AchievementType getType() {
        return type;
    }

    public AchievementValueType getValueType() {
        return valueType;
    }

    public static class OfficialAchievementInfo extends AchievementInfo {

        private final EnumSet<AchievementOfficialType> value;
        private final List<OfficialInfo> officialInfo;

        @Deprecated
        public OfficialAchievementInfo(EnumSet<AchievementOfficialType> value) {
            super(AchievementType.OFFICIAL, AchievementValueType.OFFICIAL);
            this.value = value;
            this.officialInfo = null;
        }

        @JsonCreator
        public OfficialAchievementInfo(List<OfficialInfo> officialInfo) {
            super(AchievementType.OFFICIAL, AchievementValueType.OFFICIAL);
            this.value = officialInfo.stream().map(OfficialInfo::getType)
                    .collect(Collectors.toCollection(() -> EnumSet.noneOf(AchievementOfficialType.class)));
            this.officialInfo = officialInfo;
        }

        @Description("Типы официальностей (устарело)")
        public EnumSet<AchievementOfficialType> getValue() {
            return value;
        }

        @Description("Инфа по официальностям")
        public List<OfficialInfo> getOfficialInfo() {
            return officialInfo;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            return 0;
        }
    }

    public static class PopularAchievementInfo extends AchievementInfo {

        private final Integer value;

        @JsonCreator
        public PopularAchievementInfo(@JsonProperty("value") int value) {
            super(AchievementType.POPULAR, AchievementValueType.NUMERIC);
            this.value = value == -1 ? null : value;
        }

        public Integer getValue() {
            return value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof PopularAchievementInfo) {
                return value.compareTo(((PopularAchievementInfo) o).value);
            }
            return 0;
        }
    }

    @Getter
    public static class Iks extends AchievementInfo {
        private final Integer value;

        @JsonCreator
        public Iks(@JsonProperty("value") int value) {
            super(AchievementType.IKS, AchievementValueType.NUMERIC);
            this.value = value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof Iks) {
                return value.compareTo(((Iks) o).value);
            }
            return 0;
        }
    }

    public static class UserChoiceAchievementInfo extends AchievementInfo {

        private final Integer value;

        @JsonCreator
        public UserChoiceAchievementInfo(@JsonProperty("value") int value) {
            super(AchievementType.USER_CHOICE, AchievementValueType.NUMERIC);
            this.value = value == -1 ? null : value;
        }

        public Integer getValue() {
            return value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof UserChoiceAchievementInfo) {
                return value.compareTo(((UserChoiceAchievementInfo) o).value);
            }
            return 0;
        }
    }

    public static class HttpsAchievementInfo extends AchievementInfo {
        private final boolean value;

        public HttpsAchievementInfo(boolean value) {
            super(AchievementType.HTTPS, AchievementValueType.BOOLEAN);
            this.value = value;
        }

        public boolean isValue() {
            return value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof HttpsAchievementInfo) {
                return Boolean.compare(value, ((HttpsAchievementInfo) o).value);
            }
            return 0;
        }
    }

    @Description("Информация об ИКС сайта")
    public static class SqiAchievementInfo extends AchievementInfo {

        private final String hostDisplayName;
        private final String title;
        private final Integer sqi;

        @JsonCreator
        public SqiAchievementInfo(@JsonProperty("hostDisplayName") String hostDisplayName,
                                  @JsonProperty("title") String title,
                                  @JsonProperty("sqi") Integer sqi) {
            super(AchievementType.SQI, AchievementValueType.NUMERIC);
            this.hostDisplayName = hostDisplayName;
            this.title = title;
            this.sqi = sqi;
        }

        public String getHostDisplayName() {
            return hostDisplayName;
        }

        @Description("тайтл главной страницы")
        public String getTitle() {
            return title;
        }

        @Description("значение икса")
        public Integer getSqi() {
            return sqi;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof SqiAchievementInfo) {
                return sqi.compareTo(((SqiAchievementInfo) o).sqi);
            }
            return 0;
        }
    }

    @Getter
    @Description("Информация об рейтинге сайта в Яндекс маркете")
    public static class MarketRatingInfo extends AchievementInfo {
        private final Long id;
        private final Double value;

        public MarketRatingInfo(Long id, Double value) {
            super(AchievementType.MARKET_RATING, AchievementValueType.NUMERIC);
            this.id = id;
            this.value = value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof MarketRatingInfo) {
                return value.compareTo(((MarketRatingInfo) o).value);
            }
            return 0;
        }
    }

    public static final class TasIxAchievementInfo extends AchievementInfo {

        private final boolean value;

        public TasIxAchievementInfo(boolean value) {
            super(AchievementType.TAS_IX, AchievementValueType.BOOLEAN);
            this.value = value;
        }

        public boolean isValue() {
            return value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof TasIxAchievementInfo) {
                return Boolean.compare(value, ((TasIxAchievementInfo) o).value);
            }
            return 0;
        }
    }

    @Getter
    public static final class DocsOnSearch extends AchievementInfo {
        private long value;

        public DocsOnSearch(long value) {
            super(AchievementType.DOCS_ON_SEARCH, AchievementValueType.NUMERIC);

            this.value = value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof DocsOnSearch) {
                return Long.compare(value, ((DocsOnSearch) o).value);
            }

            return 0;
        }
    }

    public static final class TurboAchievementInfo extends AchievementInfo {
        private final boolean value;

        public TurboAchievementInfo(boolean value) {
            super(AchievementType.TURBO, AchievementValueType.BOOLEAN);
            this.value = value;
        }

        public boolean isValue() {
            return value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof TurboAchievementInfo) {
                return Boolean.compare(value, ((TurboAchievementInfo) o).value);
            }

            return 0;
        }
    }

    /**
     * Скорость работы сайта. Агрегируется до владельца
     */
    public static final class MobileSpeedAchievementInfo extends AchievementInfo {
        private final Integer value;

        @JsonCreator
        public MobileSpeedAchievementInfo(@JsonProperty("value") int value) {
            super(AchievementType.MOBILE_SPEED, AchievementValueType.NUMERIC);
            this.value = value == -1 ? null : value;
        }

        public Integer getValue() {
            return value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof MobileSpeedAchievementInfo) {
                return value.compareTo(((MobileSpeedAchievementInfo) o).value);
            }

            return 0;
        }
    }

    public static final class VideohostRatingInfo extends AchievementInfo {
        private final Long value;

        @JsonCreator
        public VideohostRatingInfo(@JsonProperty("value") long value) {
            super(AchievementType.VIDEOHOST_RATING, AchievementValueType.NUMERIC);
            this.value = value;
        }

        public Long getValue() {
            return value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof VideohostRatingInfo) {
                return value.compareTo(((VideohostRatingInfo) o).value);
            }

            return 0;
        }
    }

    @Getter
    @Description("Информация о рейтинге сайта в товарной вертикали")
    public static class VerticalShareRatingInfo extends AchievementInfo {
        private final Double value;

        public VerticalShareRatingInfo(Double value) {
            super(AchievementType.VERTICAL_SHARE_RATING, AchievementValueType.NUMERIC);
            this.value = value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof VerticalShareRatingInfo) {
                return value.compareTo(((VerticalShareRatingInfo) o).value);
            }
            return 0;
        }
    }

    @Getter
    @Description("Информация о проверенности сайта в товарной вертикали")
    public static class VerticalShareIsValidatedInfo extends AchievementInfo {
        private final Boolean value;

        public VerticalShareIsValidatedInfo(Boolean value) {
            super(AchievementType.VERTICAL_SHARE_IS_VALIDATED, AchievementValueType.BOOLEAN);
            this.value = value;
        }

        @Override
        public int compareTo(@NotNull AchievementInfo o) {
            if (o instanceof VerticalShareIsValidatedInfo) {
                return value.compareTo(((VerticalShareIsValidatedInfo) o).value);
            }
            return 0;
        }
    }
}
