package click.kamil.springstatemachineexporter.analysis.flow.alloc;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * May-set of concrete allocation sites for a receiver expression / parameter.
 * Empty or multi-site facts fail closed (do not narrow virtual accessors).
 */
public final class ReceiverFacts {

    private final Set<AllocationSite> sites;

    private ReceiverFacts(Set<AllocationSite> sites) {
        this.sites = sites == null ? Set.of() : Set.copyOf(sites);
    }

    public static ReceiverFacts empty() {
        return new ReceiverFacts(Set.of());
    }

    public static ReceiverFacts of(AllocationSite site) {
        if (site == null || site.typeFqn() == null || site.typeFqn().isBlank()) {
            return empty();
        }
        return new ReceiverFacts(Set.of(site));
    }

    public static ReceiverFacts ofAll(Iterable<AllocationSite> sites) {
        // Merge by type FQN, preferring sites that retain CIC AST.
        Map<String, AllocationSite> byType = new LinkedHashMap<>();
        if (sites != null) {
            for (AllocationSite site : sites) {
                if (site == null || site.typeFqn() == null || site.typeFqn().isBlank()) {
                    continue;
                }
                AllocationSite existing = byType.get(site.typeFqn());
                byType.put(site.typeFqn(), existing == null ? site : existing.preferRich(site));
            }
        }
        return new ReceiverFacts(Set.copyOf(byType.values()));
    }

    public boolean isEmpty() {
        return sites.isEmpty();
    }

    public boolean isUnique() {
        return sites.size() == 1;
    }

    public AllocationSite uniqueOrNull() {
        return isUnique() ? sites.iterator().next() : null;
    }

    public List<AllocationSite> sites() {
        return List.copyOf(sites);
    }

    public int size() {
        return sites.size();
    }
}
