package click.kamil.springstatemachineexporter.analysis.index;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class AccessorIndex {

    private static final AccessorIndex EMPTY = new AccessorIndex(Map.of(), 0, 0, 0);

    private final Map<String, Map<String, AccessorSummary>> byOwnerAndMethod;
    private final int typeCount;
    private final int trivialCount;
    private final int blockedCount;

    public AccessorIndex(
            Map<String, Map<String, AccessorSummary>> byOwnerAndMethod,
            int typeCount,
            int trivialCount,
            int blockedCount) {
        this.byOwnerAndMethod = Collections.unmodifiableMap(deepCopy(byOwnerAndMethod));
        this.typeCount = typeCount;
        this.trivialCount = trivialCount;
        this.blockedCount = blockedCount;
    }

    public static AccessorIndex empty() {
        return EMPTY;
    }

    public Optional<AccessorSummary> lookup(String ownerFqn, String methodName) {
        if (ownerFqn == null || methodName == null) {
            return Optional.empty();
        }
        Map<String, AccessorSummary> methods = byOwnerAndMethod.get(ownerFqn);
        if (methods == null) {
            return Optional.empty();
        }
        return Optional.ofNullable(methods.get(methodName));
    }

    public List<AccessorSummary> accessorsForType(String ownerFqn) {
        Map<String, AccessorSummary> methods = byOwnerAndMethod.get(ownerFqn);
        if (methods == null) {
            return List.of();
        }
        return List.copyOf(methods.values());
    }

    public Map<String, Map<String, AccessorSummary>> asMap() {
        return byOwnerAndMethod;
    }

    public int typeCount() {
        return typeCount;
    }

    public int trivialCount() {
        return trivialCount;
    }

    public int blockedCount() {
        return blockedCount;
    }

    private static Map<String, Map<String, AccessorSummary>> deepCopy(Map<String, Map<String, AccessorSummary>> source) {
        Map<String, Map<String, AccessorSummary>> copy = new HashMap<>();
        for (Map.Entry<String, Map<String, AccessorSummary>> entry : source.entrySet()) {
            copy.put(entry.getKey(), Map.copyOf(entry.getValue()));
        }
        return copy;
    }
}
