package gui.widget;

import java.util.ArrayList;
import java.util.List;

import common.ConsumerSignal;
import gui.constants.SudokuType;
import imgui.ImGui;
import imgui.extension.imguifiledialog.ImGuiFileDialog;
import imgui.extension.imguifiledialog.flag.ImGuiFileDialogFlags;
import imgui.type.ImBoolean;
import imgui.type.ImInt;
import sudoku.constraint.Constraint;
import sudoku.constraint.IConstraint;
import sudoku.structure.Difficulty;
import sudoku.structure.MultiDoku;
import sudoku.structure.SudokuFactory;

public class SudokuSelector {

	public final ConsumerSignal<MultiDoku> onSelect = new ConsumerSignal<>();
	private MultiDoku doku;

	private final boolean canGenEmptyGrid;

	private final ImInt sudokuType = new ImInt(0);

	private final ImInt difficulty = new ImInt(Difficulty.Easy.ordinal());
	private final List<ImBoolean> contraints = new ArrayList<>();

	private final ImInt sudokuSize = new ImInt(3);

	private final ImInt sudokuWidth = new ImInt(3);
	private final ImInt sudokuHeight = new ImInt(3);

	private final String confirmMessage;

	public SudokuSelector(boolean canGenEmptyGrid, String confirmMessage) {
		this.canGenEmptyGrid = canGenEmptyGrid;
		this.confirmMessage = confirmMessage;
		initConstraints();
	}

	private List<IConstraint> getConstraints() {
		List<IConstraint> constraints = new ArrayList<>();
		for (int i = 0; i < this.contraints.size(); i++) {
			if (this.contraints.get(i).get())
				constraints.add(Constraint.values()[i].getConstraint());
		}
		return constraints;
	}

	private void initConstraints() {
		for (Constraint cons : Constraint.values()) {
			contraints.add(new ImBoolean(SudokuFactory.DEFAULT_CONSTRAINTS.contains(cons.getConstraint())));
		}
	}

	private void selectSudoku(MultiDoku doku, boolean empty) {
		this.doku = doku;
		if (!empty) {
			try {
				SudokuFactory.fillDoku(doku, Difficulty.values()[difficulty.get()]);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		this.onSelect.emit(this.doku);
	}

	public void renderFileDialog() {
		if (ImGuiFileDialog.display("browse-sudoku", ImGuiFileDialogFlags.None)) {
			if (ImGuiFileDialog.isOk()) {
				var selection = ImGuiFileDialog.getSelection();
				for (var entry : selection.entrySet()) {
					try {
						String filePath = entry.getValue();
						this.doku = SudokuFactory.fromfile(filePath);
						if (this.doku != null)
							this.onSelect.emit(this.doku);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
			ImGuiFileDialog.close();
		}
	}

	public void render() {
		ImGui.combo("Difficulté", difficulty, Difficulty.getDifficultyNames());
		if (ImGui.treeNode("Constraintes")) {
			for (Constraint cons : Constraint.values()) {
				ImGui.checkbox(cons.getDisplayName(), contraints.get(cons.ordinal()));
			}
			ImGui.treePop();
		}
		ImGui.combo("Type de Sudoku", sudokuType, SudokuType.getTypeNames());
		SudokuType currentType = SudokuType.values()[sudokuType.get()];
		switch (currentType.getMakerParamCount()) {
			case 1:
				if (ImGui.inputInt("Taille", sudokuSize))
					sudokuSize.set(Math.clamp(sudokuSize.get(), 1, 10));
				if (ImGui.button(confirmMessage)) {
					selectSudoku(currentType.createDoku(getConstraints(), sudokuSize.get()), false);
				}
				if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) {
					selectSudoku(currentType.createDoku(getConstraints(), sudokuSize.get()), true);
				}
				break;

			case 2:
				if (ImGui.inputInt("Longueur", sudokuWidth))
					sudokuWidth.set(Math.clamp(sudokuWidth.get(), 1, 10));
				if (ImGui.inputInt("Hauteur", sudokuHeight))
					sudokuHeight.set(Math.clamp(sudokuHeight.get(), 1, 10));
				if (ImGui.button(confirmMessage)) {
					selectSudoku(currentType.createDoku(getConstraints(), sudokuWidth.get(), sudokuHeight.get()),
							false);
				}
				if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) {
					selectSudoku(currentType.createDoku(getConstraints(), sudokuWidth.get(), sudokuHeight.get()), true);
				}
				break;

			default:
				assert (false);
				break;
		}

		if (ImGui.button("À partir d'un fichier")) {
			ImGuiFileDialog.openDialog("browse-sudoku", "Choisissez un fichier", ".json", ".");
		}
		renderFileDialog();
	}

}
