package cz.jzitnik.game.crafting;

import cz.jzitnik.game.entities.items.InventoryItem;
import cz.jzitnik.game.entities.items.ItemBlockSupplier;
import cz.jzitnik.game.annotations.CraftingRecipeRegistry;
import org.reflections.Reflections;

import java.util.*;

public class CraftingRecipeList {
    public static final List<CraftingRecipe> recipes = new ArrayList<>();

    static {
        registerRecipes();
    }

    private static void registerRecipes() {
        Reflections reflections = new Reflections("cz.jzitnik.game.crafting.recipes");
        Set<Class<?>> recipeClasses = reflections.getTypesAnnotatedWith(CraftingRecipeRegistry.class);

        for (Class<?> clazz : recipeClasses) {
            try {
                CraftingRecipeRegistry annotation = clazz.getAnnotation(CraftingRecipeRegistry.class);
                String[][] recipeGrid = convertTo2DGrid(annotation.recipe());

                recipes.add(new CraftingRecipe(recipeGrid,
                        () -> new InventoryItem(annotation.amount(), ItemBlockSupplier.getItem(annotation.result())),
                        annotation.usingRegex()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static String[][] convertTo2DGrid(String[] flatGrid) {
        int size = (int) Math.sqrt(flatGrid.length); // Assumes 3x3
        String[][] grid = new String[size][size];

        for (int i = 0; i < size; i++) {
            System.arraycopy(flatGrid, i * size, grid[i], 0, size);
        }

        // Convert "_" placeholders back to null
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (grid[i][j].equals("_")) {
                    grid[i][j] = null;
                }
            }
        }

        return grid;
    }

    public static Optional<CraftingRecipe> getRecipe(String[] r) {
        for (CraftingRecipe recipe : recipes) {
            if (matchesByItemSet(recipe.getRecipe(), r, recipe.isUsingRegex())) {
                return Optional.of(recipe);
            }
        }
        return Optional.empty();
    }

    public static String[][] trimNullEdges(String[][] array) {
        int n = array.length;
        int minRow = n, maxRow = -1, minCol = n, maxCol = -1;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (array[i][j] != null) {
                    minRow = Math.min(minRow, i);
                    maxRow = Math.max(maxRow, i);
                    minCol = Math.min(minCol, j);
                    maxCol = Math.max(maxCol, j);
                }
            }
        }

        if (maxRow == -1) {
            return new String[0][0];
        }

        int newSizeRow = maxRow - minRow + 1;
        int newSizeCol = maxCol - minCol + 1;
        String[][] trimmedArray = new String[newSizeRow][newSizeCol];

        for (int i = 0; i < newSizeRow; i++) {
            System.arraycopy(array[minRow + i], minCol, trimmedArray[i], 0, newSizeCol);
        }

        return trimmedArray;
    }

    public static boolean are2DArraysIdentical(String[][] array1, String[][] array2, boolean usingRegex) {
        if (array1 == null || array2 == null) {
            return array1 == array2;
        }

        if (array1.length != array2.length) {
            return false;
        }

        for (int i = 0; i < array1.length; i++) {
            if (array1[i] == null || array2[i] == null) {
                if (array1[i] != array2[i]) return false;
                continue;
            }

            if (array1[i].length != array2[i].length) {
                return false;
            }

            for (int j = 0; j < array1[i].length; j++) {
                String a = array1[i][j];
                String b = array2[i][j];

                if (a == null || b == null) {
                    if (a != b) return false; // one null, one not -> false
                } else {
                    boolean equal = usingRegex ? b.matches(a) : a.equals(b);
                    if (!equal) return false;
                }
            }
        }

        return true;
    }

    private static boolean matchesByItemSet(String[][] recipe, String[] grid, boolean usingRegex) {
        String[][] finalGrid = new String[3][3];

        if (grid.length == 4) {
            finalGrid[0][0] = grid[0];
            finalGrid[0][1] = grid[1];
            finalGrid[1][0] = grid[2];
            finalGrid[1][1] = grid[3];
        } else {
            finalGrid[0][0] = grid[0];
            finalGrid[0][1] = grid[1];
            finalGrid[0][2] = grid[2];
            finalGrid[1][0] = grid[3];
            finalGrid[1][1] = grid[4];
            finalGrid[1][2] = grid[5];
            finalGrid[2][0] = grid[6];
            finalGrid[2][1] = grid[7];
            finalGrid[2][2] = grid[8];
        }

        var croppedRecipe = trimNullEdges(recipe);
        var croppedGrid = trimNullEdges(finalGrid);

        return are2DArraysIdentical(croppedRecipe, croppedGrid, usingRegex);
    }
}
