package mb.statix.solver;

import static mb.nabl2.terms.build.TermBuild.B;

import java.util.Set;

import org.immutables.serial.Serial;
import org.immutables.value.Value;

import com.google.common.collect.ImmutableSet;

import mb.nabl2.scopegraph.terms.ImmutableScope;
import mb.nabl2.terms.ITerm;
import mb.nabl2.terms.ITermVar;
import mb.nabl2.terms.unification.IUnifier;
import mb.nabl2.terms.unification.PersistentUnifier;
import mb.nabl2.util.ImmutableTuple2;
import mb.nabl2.util.Tuple2;
import mb.statix.scopegraph.IScopeGraph;
import mb.statix.scopegraph.reference.ScopeGraph;
import mb.statix.spec.Spec;

@Value.Immutable
@Serial.Version(value = 42L)
public abstract class AState {

    @Value.Parameter public abstract Spec spec();

    // --- variables ---

    @Value.Default int __varCounter() {
        return 0;
    }

    @Value.Default Set<ITermVar> __vars() {
        return ImmutableSet.of();
    }

    public Tuple2<ITermVar, State> freshVar(String base) {
        final int i = __varCounter() + 1;
        final String name = base.replaceAll("-", "_") + "-" + i;
        final ITermVar var = B.newVar("", name);
        return ImmutableTuple2.of(var, State.builder().from(this).__varCounter(i).add__vars(var).build());
    }

    public Set<ITermVar> vars() {
        return __vars();
    }

    // --- scopes ---

    @Value.Default int __scopeCounter() {
        return 0;
    }

    @Value.Default Set<ITerm> __scopes() {
        return ImmutableSet.of();
    }

    public Tuple2<ITerm, State> freshScope(String base) {
        final int i = __scopeCounter() + 1;
        final String name = base.replaceAll("-", "_") + "-" + i;
        final ITerm scope = ImmutableScope.of("", name);
        return ImmutableTuple2.of(scope, State.builder().from(this).__scopeCounter(i).add__scopes(scope).build());
    }

    public Set<ITerm> scopes() {
        return __scopes();
    }

    // --- solution ---

    @Value.Default public IUnifier.Immutable unifier() {
        return PersistentUnifier.Immutable.of();
    }

    @Value.Default public IScopeGraph.Immutable<ITerm, ITerm, ITerm> scopeGraph() {
        return ScopeGraph.Immutable.of(spec().labels(), spec().endOfPath(), spec().relations().keySet());
    }

}
@@ -73,31 +73,8 @@
 B;%0A%0A
-import java.util.Set;%0A%0A
 impo
@@ -153,49 +153,37 @@
 ort 
-com.google.common.collect.Immutab
+io.usethesource.capsu
 le
+.
 Set;%0A
-%0A
 impo
@@ -810,24 +810,34 @@
 .Default Set
+.Immutable
 %3CITermVar%3E _
@@ -853,32 +853,36 @@
 %0A        return 
+Set.
 ImmutableSet.of(
@@ -866,35 +866,32 @@
 rn Set.Immutable
-Set
 .of();%0A    %7D%0A%0A  
@@ -1095,32 +1095,101 @@
 wVar(%22%22, name);%0A
+        final Set.Immutable%3CITermVar%3E vars = __vars().__insert(var);%0A
         return I
@@ -1254,19 +1254,16 @@
 nter(i).
-add
 __vars(v
@@ -1264,16 +1264,17 @@
 vars(var
+s
 ).build(
@@ -1294,24 +1294,34 @@
   public Set
+.Immutable
 %3CITermVar%3E v
@@ -1468,24 +1468,34 @@
 .Default Set
+.Immutable
 %3CITerm%3E __sc
@@ -1510,32 +1510,36 @@
 %0A        return 
+Set.
 ImmutableSet.of(
@@ -1531,19 +1531,16 @@
 mmutable
-Set
 .of();%0A 
@@ -1761,32 +1761,104 @@
 e.of(%22%22, name);%0A
+        final Set.Immutable%3CITerm%3E scopes = __scopes().__insert(scope);%0A
         return I
@@ -1931,11 +1931,8 @@
 (i).
-add
 __sc
@@ -1941,16 +1941,17 @@
 es(scope
+s
 ).build(
@@ -1975,16 +1975,26 @@
 blic Set
+.Immutable
 %3CITerm%3E 

Switch immutable set implementation.