package ru.yandex.webmaster3.core.util.json.polymorphic;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DatabindContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.type.TypeFactory;
import ru.yandex.webmaster3.core.http.autodoc.FullTypeInfo;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;

/**
 * @author avhaliullin
 */
public class DiscriminatorBasedTypeResolver implements TypeIdResolver {
    private final Map<String, JavaType> id2Type = new HashMap<>();

    @Override
    public void init(JavaType baseType) {
        FullTypeInfo baseTypeInfo = FullTypeInfo.createSimple(baseType.getRawClass());
        FullTypeInfo poly = baseTypeInfo.ancestorFullType(Polymorphic.class);
        Class discriminatorType = poly.getGenericsList().get(0).getClazz();
        for (Object enumValue : discriminatorType.getEnumConstants()) {
            Class dataClass = ((Discriminator) enumValue).getDataClass();
            if (baseType.getRawClass().isAssignableFrom(dataClass)) {
                id2Type.put(
                        ((Discriminator) enumValue).getDiscriminatorId(),
                        TypeFactory.defaultInstance().constructSpecializedType(baseType, dataClass)
                );
            }
        }
    }

    @Override
    public String idFromValue(Object value) {
        return ((Polymorphic) value).getType().toString();
    }

    @Override
    public String idFromValueAndType(Object value, Class<?> suggestedType) {
        return idFromValue(value);
    }

    @Override
    public String idFromBaseType() {
        throw new UnsupportedOperationException();
    }

    public JavaType typeFromId(String id) {
        return id2Type.get(id.toLowerCase());
    }

    @Override
    public JavaType typeFromId(DatabindContext context, String id) {
        return typeFromId(id);
    }

    @Override
    public String getDescForKnownTypeIds() {
        return new TreeSet<>(id2Type.keySet()).toString();
    }

    @Override
    public JsonTypeInfo.Id getMechanism() {
        return JsonTypeInfo.Id.CUSTOM;
    }
}
