package ru.nbch.credit_tracker.enums;

import java.io.Serializable;
import java.util.Objects;

public interface IEnumKeyCode extends Serializable {
    String getKey();
    String getCode();

    default boolean equalsByKey(String key) {
        return key != null && getKey().equalsIgnoreCase(key);
    }

    /**
     * Проверяет что среди данного набора Enum, присутствует элемент с данным id
     * id может быть null
     */
    static <T extends Enum<T> & IEnumKeyCode> boolean contains(String id, T... enumSet) {
        for (T e : enumSet) {
            if (Objects.equals(id, e.getKey()))
                return true;
        }
        return false;
    }
    static <T extends Enum<T> & IEnumKeyCode> boolean containsIgnoreCase(String id, T... enumSet) {
        for (T e : enumSet) {
            if (e.getKey() != null && e.getKey().equalsIgnoreCase(id)) {
                return true;
            }
        }
        return false;
    }

    static <T extends Enum<T> & IEnumKeyCode> boolean contains(T e, T... enumSet) {
        for (T enumEl : enumSet) {
            if (enumEl.equals(e))
                return true;
        }
        return false;
    }

    /**
     * Проверяет что среди всех Enum данного класса, присутствует элемент с данным id
     * id может быть null
     */
    static <T extends Enum<T> & IEnumKeyCode> boolean contains(String key, Class<T> enumClass) {
        for (T e : enumClass.getEnumConstants()) {
            if (Objects.equals(key, e.getKey()))
                return true;
        }
        return false;
    }

    /**
     * Возвращает Enum по id, если в заданном классе такой определен
     * id может быть null
     *
     * @return Enum если нашел, иначе <tt>null</tt>
     */
    static <T extends Enum<T> & IEnumKeyCode> T getEnumByKey(Class<T> enumClass, String key) {
        for (T e : enumClass.getEnumConstants()) {
            if (Objects.equals(key, e.getKey()))
                return e;
        }
        return null;
    }

    static <T extends Enum<T> & IEnumKeyCode> T getEnumByKeyOrUndefined(Class<T> enumClass, String key) {
        T enumByKey = getEnumByKey(enumClass, key);
        return enumByKey == null ? getUndefined(enumClass) : enumByKey;
    }

    static <T extends Enum<T> & IEnumKeyCode> T getUndefined(Class<T> enumClass) {
        T enumByKey = getEnumByKey(enumClass, UNDEFINED_VALUE);
        if (enumByKey == null) {
            throw new IllegalArgumentException("Undefined value not found in enum " + enumClass);
        }
        return enumByKey;
    }

    default boolean theSameAs(Object other) {
        if (!(other instanceof IEnumKeyCode otherCasted)) {
            return false;
        }
        return this.getKey().equalsIgnoreCase(otherCasted.getKey());
    }

    default String getErrorCode() {
        String key = getKey();
        String[] split = key.split("\\.");
        if (split.length < 1) return null;
        String s = split[split.length - 1];
        if (!s.matches("\\d+")) return null;
        return s;
    }

    static String getKeyOrNull(IEnumKeyCode enumVal) {
        return enumVal == null ? null : enumVal.getKey();
    }

    String UNDEFINED_VALUE = "_Undefined";
}
