package server;

import de.dhbwstuttgart.parser.SourceLoc;
import de.dhbwstuttgart.typeinference.constraints.Constraint;
import de.dhbwstuttgart.typeinference.constraints.ConstraintSet;
import de.dhbwstuttgart.typeinference.unify.PlaceholderRegistry;
import de.dhbwstuttgart.typeinference.unify.UnifyContext;
import de.dhbwstuttgart.typeinference.unify.UnifyResultModel;
import de.dhbwstuttgart.typeinference.unify.UnifyTaskModel;
import de.dhbwstuttgart.typeinference.unify.model.ExtendsType;
import de.dhbwstuttgart.typeinference.unify.model.FiniteClosure;
import de.dhbwstuttgart.typeinference.unify.model.FunInterfaceType;
import de.dhbwstuttgart.typeinference.unify.model.FunNType;
import de.dhbwstuttgart.typeinference.unify.model.PairOperator;
import de.dhbwstuttgart.typeinference.unify.model.PlaceholderType;
import de.dhbwstuttgart.typeinference.unify.model.ReferenceType;
import de.dhbwstuttgart.typeinference.unify.model.SuperType;
import de.dhbwstuttgart.typeinference.unify.model.TypeParams;
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
import de.dhbwstuttgart.typeinference.unify.model.UnifyType;
import de.dhbwstuttgart.util.Logger;
import java.io.Writer;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ForkJoinPool;

class PacketExampleData {

  static ConstraintSet<UnifyPair> getExampleUnifyPairConstraintSet(
    UnifyContext unifyContext, String packagePath, int numUndCons, int numOderCons
  ) {
    var constraintSet = new ConstraintSet<UnifyPair>();
    for (int i = 0; i < numUndCons; i++) {
      constraintSet.addUndConstraint(
        getExampleUnifyPair(unifyContext, packagePath+"undCons.")
      );
    }
    for (int i = 0; i < numOderCons; i++) {
      var oderConstraint = new HashSet<Constraint<UnifyPair>>();
      getExampleUnifyPairConstraint(unifyContext, packagePath+"oderCons.", i == 0);
      constraintSet.addOderConstraint(oderConstraint);
    }
    return constraintSet;
  }

  static Constraint<UnifyPair> getExampleUnifyPairConstraint(UnifyContext unifyContext, String packagePath, boolean withExtends) {
    return new Constraint<>(
      !withExtends, true,
      withExtends ? getExampleUnifyPairConstraint(unifyContext, packagePath+"extendConstraint.", false) : null,
      withExtends ? new HashSet<>(List.of(
        getExampleUnifyPair(unifyContext, packagePath+"methodSignatureConstraint.zero."),
        getExampleUnifyPair(unifyContext, packagePath+"methodSignatureConstraint.one.")
      )) : null
    );
  }

  static UnifyPair getExampleUnifyPair(UnifyContext unifyContext, String packagePath) {
    return new UnifyPair(
      new ReferenceType(packagePath + "something", false),
      new ExtendsType(
        new SuperType(
          new FunInterfaceType("lambda" + unifyContext.placeholderRegistry().generateFreshPlaceholderName(),
            new TypeParams(),
            List.of( // intfArgTypes
              FunNType.getFunNType(new TypeParams(
                List.of(
                  PlaceholderType.freshPlaceholder(unifyContext.placeholderRegistry()),
                  PlaceholderType.freshPlaceholder(unifyContext.placeholderRegistry())
                )
              ))
            ),
            PlaceholderType.freshPlaceholder(unifyContext.placeholderRegistry()), // intfReturnType
            List.of( // generics
              "ZA",
              "ZB",
              unifyContext.placeholderRegistry().generateFreshPlaceholderName()
            )
          )
        )
      ),
      PairOperator.SMALLERDOT,
      new SourceLoc("test.jav", 10)
    );
  }

  static UnifyContext createTestContext() {
    var placeholderRegistry = new PlaceholderRegistry();
    return new UnifyContext(Logger.NULL_LOGGER, true,
      new UnifyResultModel(
        new ConstraintSet<>(),
        new FiniteClosure(
          new HashSet<>(),
          Logger.NULL_LOGGER,
          placeholderRegistry)),
      new UnifyTaskModel(),
      ForkJoinPool.commonPool(),
      placeholderRegistry
    );
  }

}
