package lama.sqlite3.gen;

import java.util.List;
import java.util.stream.Collectors;

import lama.Randomly;
import lama.sqlite3.SQLite3Provider.SQLite3GlobalState;
import lama.sqlite3.SQLite3Visitor;
import lama.sqlite3.schema.SQLite3Schema.Column;

public class SQLite3ColumnBuilder {

	private boolean containsPrimaryKey;
	private boolean containsAutoIncrement;
	private final StringBuilder sb = new StringBuilder();
	private boolean conflictClauseInserted;

	private boolean allowPrimaryKey = true;
	private boolean allowUnique = true;
	private boolean allowDefaultValue = true;
	private boolean allowCheck = true;
	private boolean allowNotNull = true;

	private enum Constraints {
		NOT_NULL, PRIMARY_KEY, UNIQUE, CHECK, GENERATED_AS
	}

	public boolean isContainsAutoIncrement() {
		return containsAutoIncrement;
	}

	public boolean isConflictClauseInserted() {
		return conflictClauseInserted;
	}

	public boolean isContainsPrimaryKey() {
		return containsPrimaryKey;
	}

	public String createColumn(String columnName, SQLite3GlobalState globalState, List<Column> columns) {
		sb.append(columnName);
		sb.append(" ");
		String dataType = Randomly.fromOptions("INT", "TEXT", "BLOB", "REAL", "INTEGER");
		sb.append(dataType);

		if (Randomly.getBoolean()) {
			List<Constraints> constraints = Randomly.subset(Constraints.values());
			if (constraints.contains(Constraints.GENERATED_AS)) {
				allowDefaultValue = false;
				allowPrimaryKey = false;
			}
			for (Constraints c : constraints) {
				switch (c) {
				case GENERATED_AS:
					sb.append(" GENERATED ALWAYS AS (");
					sb.append(SQLite3Visitor.asString(new SQLite3ExpressionGenerator(globalState).deterministicOnly().setColumns(columns.stream().filter(p -> !p.getName().contentEquals(columnName)).collect(Collectors.toList())).getRandomExpression()));
					sb.append(")");
					break;
				case PRIMARY_KEY:
					// only one primary key is allow if not specified as table constraint
					if (allowPrimaryKey) {
						sb.append(" PRIMARY KEY");
						containsPrimaryKey = true;
						boolean hasOrdering = Randomly.getBoolean();
						if (hasOrdering) {
							if (Randomly.getBoolean()) {
								sb.append(" ASC");
							} else {
								sb.append(" DESC");
							}
						}
						if (Randomly.getBoolean()) {
							insertOnConflictClause();
						}
						if (!hasOrdering && dataType.equals("INTEGER")) {
							if (Randomly.getBoolean()) {
								containsAutoIncrement = true;
								sb.append(" AUTOINCREMENT");
							}
						}
					}
					break;
				case UNIQUE:
					if (allowUnique) {
						sb.append(" UNIQUE");
						if (Randomly.getBoolean()) {
							insertOnConflictClause();
						}
					}
					break;
				case NOT_NULL:
					if (allowNotNull) {
						sb.append(" NOT NULL");
						if (Randomly.getBoolean()) {
							insertOnConflictClause();
						}
					}
					break;
				case CHECK:
					if (allowCheck) {
						sb.append(SQLite3Common.getCheckConstraint(globalState, columns));
					}
					break;
				default:
					throw new AssertionError();
				}
			}
		}
		if (allowDefaultValue && Randomly.getBooleanWithSmallProbability()) {
			sb.append(" DEFAULT " + SQLite3Visitor.asString(SQLite3ExpressionGenerator.getRandomLiteralValue(globalState)));
		}
		if (Randomly.getBooleanWithSmallProbability()) {
			String randomCollate = SQLite3Common.getRandomCollate();
			sb.append(randomCollate);
		}
		return sb.toString();
	}

	// it seems that only one conflict clause can be inserted
	private void insertOnConflictClause() {
		if (!conflictClauseInserted) {
			sb.append(" ON CONFLICT ");
			sb.append(Randomly.fromOptions("ROLLBACK", "ABORT", "FAIL", "IGNORE", "REPLACE"));
			conflictClauseInserted = true;
		}
	}

	public SQLite3ColumnBuilder allowPrimaryKey(boolean allowPrimaryKey) {
		this.allowPrimaryKey = allowPrimaryKey;
		return this;
	}

	public SQLite3ColumnBuilder allowUnique(boolean allowUnique) {
		this.allowUnique = allowUnique;
		return this;
	}

	public SQLite3ColumnBuilder allowDefaultValue(boolean allowDefaultValue) {
		this.allowDefaultValue = allowDefaultValue;
		return this;
	}

	public SQLite3ColumnBuilder allowCheck(boolean allowCheck) {
		this.allowCheck = allowCheck;
		return this;
	}

	public SQLite3ColumnBuilder allowNotNull(boolean allowNotNull) {
		this.allowNotNull = allowNotNull;
		return this;
	}

}

@@ -1331,16 +1331,124 @@
 ues());%0A
+%09%09%09if (!Randomly.getBooleanWithSmallProbability()) %7B%0A%09%09%09%09constraints.remove(Constraints.GENERATED_AS);%0A%09%09%09%7D%0A
 %09%09%09if (c

Make it less likely to generate generated columns