package click.kamil.springstatemachineexporter.analysis.pipeline;

import java.util.AbstractMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Memoizes polymorphic class compatibility checks used during call-graph path matching.
 */
public final class ClassCompatibilityCache {

    private final Map<Map.Entry<String, String>, Boolean> cache = new ConcurrentHashMap<>();
    private final Map<String, Object> memoCache = new ConcurrentHashMap<>();

    public boolean areClassesCompatible(String classNeighbor, String classTarget, ClassCompatibilityChecker checker) {
        if (classNeighbor == null || classTarget == null) {
            return false;
        }
        if (classNeighbor.equals(classTarget)) {
            return true;
        }
        Map.Entry<String, String> key = cacheKey(classNeighbor, classTarget);
        return cache.computeIfAbsent(key, ignored -> checker.check(classNeighbor, classTarget));
    }

    @SuppressWarnings("unchecked")
    public <T> T memoize(String key, java.util.function.Function<String, T> computer) {
        return (T) memoCache.computeIfAbsent(key, computer);
    }

    public void clearMemoCache() {
        memoCache.clear();
    }

    public void clear() {
        cache.clear();
        memoCache.clear();
    }

    private static Map.Entry<String, String> cacheKey(String classNeighbor, String classTarget) {
        if (classNeighbor.compareTo(classTarget) <= 0) {
            return new AbstractMap.SimpleImmutableEntry<>(classNeighbor, classTarget);
        }
        return new AbstractMap.SimpleImmutableEntry<>(classTarget, classNeighbor);
    }

    @FunctionalInterface
    public interface ClassCompatibilityChecker {
        boolean check(String classNeighbor, String classTarget);
    }
}
