package com.zfire.jiasm.syncdata.api;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.lang3.math.NumberUtils;
import org.mapstruct.Named;
import org.mapstruct.TargetType;

import java.util.Arrays;
import java.util.Optional;

/**
 * @description: 枚举基类
 * @author: qinrongjun
 * @date: 2023/3/10 15:34
 **/
public interface BaseEnum {
    String getKey();
    String getValue();

    @JsonIgnore
    default Integer getIntKey() {
        return Optional.ofNullable(getKey())
                .filter(NumberUtils::isCreatable)
                .map(Integer::valueOf)
                .orElse(null);
    }


    /**
     * 通用转换对应的枚举实例
     * @param clazz 枚举类型
     * @param key 枚举的key字段值
     * @return
     */
    @Named("keyToEnum")
    static <T extends BaseEnum> T keyToEnum(@TargetType Class<T> clazz, String key) {
        if (!clazz.isEnum() | !BaseEnum.class.isAssignableFrom(clazz)) {
            return null;
        }
        return Arrays.stream(clazz.getEnumConstants())
                .filter(item -> item.getKey().equals(key))
                .findAny()
                .orElse(null);

    }

    @Named("intKeyToEnum")
    static <T extends BaseEnum> T intKeyToEnum(@TargetType Class<T> clazz, Integer key) {
        if (!clazz.isEnum() | !BaseEnum.class.isAssignableFrom(clazz)) {
            return null;
        }
        return Arrays.stream(clazz.getEnumConstants())
                .filter(item -> item.getIntKey().equals(key))
                .findAny()
                .orElse(null);

    }

    @Named("intKeyToEnum")
    static <T extends BaseEnum> Optional<T> intKeyToEnumOpt(@TargetType Class<T> clazz, Integer key) {
        return Optional.ofNullable(intKeyToEnum(clazz, key));
    }

    @Named("intKeyToValue")
    static String intKeyToValue(@TargetType Class<? extends BaseEnum> clazz, Integer key) {
        if (!clazz.isEnum() | !BaseEnum.class.isAssignableFrom(clazz)) {
            return null;
        }
        return Arrays.stream(clazz.getEnumConstants())
                .filter(item -> item.getIntKey().equals(key))
                .findAny()
                .map(BaseEnum::getValue)
                .orElse(null);

    }

    @Named("keyToValue")
    static String keyToValue(@TargetType Class<? extends BaseEnum> clazz, String key) {
        if (!clazz.isEnum() | !BaseEnum.class.isAssignableFrom(clazz)) {
            return null;
        }
        return Arrays.stream(clazz.getEnumConstants())
                .filter(item -> item.getKey().equals(key))
                .findAny()
                .map(BaseEnum::getValue)
                .orElse(null);

    }

    @Named("keyToValueOpt")
    static Optional<String> keyToValueOpt(@TargetType Class<? extends BaseEnum> clazz, String key) {
        return Optional.ofNullable(keyToValue(clazz,key));

    }

    static <T extends BaseEnum> Optional<T> keyToEnumOpt(@TargetType Class<T> clazz, String key) {
        return Optional.ofNullable(keyToEnum(clazz, key));
    }

    @Named("enumToKey")
    static String enumToKey(BaseEnum baseEnum) {
        if (baseEnum == null) {
            return null;
        }
        return baseEnum.getKey();
    }

    @Named("enumToIntKey")
    static Integer enumToIntKey(BaseEnum baseEnum) {
        if (baseEnum == null) {
            return null;
        }
        return baseEnum.getIntKey();
    }

    @Named("valueToEnum")
    static <T extends BaseEnum> T valueToEnum(@TargetType Class<T> clazz, String value) {
        if (!clazz.isEnum() | !BaseEnum.class.isAssignableFrom(clazz)) {
            return null;
        }
        return Arrays.stream(clazz.getEnumConstants())
                .filter(item -> item.getValue().equals(value))
                .findAny()
                .orElse(null);

    }

    @Named("valueToKey")
    static String valueToKey(@TargetType Class<? extends BaseEnum> clazz, String value) {
        if (!clazz.isEnum() | !BaseEnum.class.isAssignableFrom(clazz)) {
            return null;
        }
        return Arrays.stream(clazz.getEnumConstants())
                .filter(item -> item.getValue().equals(value))
                .findAny()
                .map(BaseEnum::getKey)
                .orElse(null);

    }

    @Named("valueToIntKey")
    static Integer valueToIntKey(@TargetType Class<? extends BaseEnum> clazz, String value) {
        if (!clazz.isEnum() | !BaseEnum.class.isAssignableFrom(clazz)) {
            return null;
        }
        return Arrays.stream(clazz.getEnumConstants())
                .filter(item -> item.getValue().equals(value))
                .findAny()
                .map(BaseEnum::getIntKey)
                .orElse(null);

    }

    static <T extends BaseEnum> Optional<T> valueToEnumOpt(@TargetType Class<T> clazz, String value) {
        return Optional.ofNullable(valueToEnum(clazz, value));
    }
}
