package cz.jzitnik.game.ui;

import cz.jzitnik.game.Game;
import cz.jzitnik.game.crafting.CraftingRecipe;
import cz.jzitnik.game.crafting.CraftingRecipeList;
import cz.jzitnik.game.entities.items.InventoryItem;
import cz.jzitnik.tui.utils.SpriteCombiner;
import cz.jzitnik.tui.SpriteList;
import cz.jzitnik.tui.utils.Numbers;
import lombok.Getter;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * Represents a small 2x2 crafting table that allows crafting of items
 * based on defined recipes.
 */
public class SmallCraftingTable {

    /** Number of rows in the crafting grid. */
    public static final int ROW_AMOUNT = 2;

    /** Number of columns in the crafting grid. */
    public static final int COLUMN_AMOUNT = 2;

    /** The inventory associated with the crafting table. */
    private Inventory inventory;

    /** The items currently placed in the crafting grid. */
    @Getter
    private InventoryItem[] items = new InventoryItem[4];

    /**
     * Attempts to craft an item based on the items in the crafting grid.
     * If a matching recipe is found, the crafted item is added to the inventory,
     * and input items are consumed.
     */
    public void pickup() {
        Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipe(Arrays.stream(items)
                .map(item -> item == null ? null : item.getItem().getFirst().getId()).toArray(String[]::new));

        if (recipe.isPresent()) {
            InventoryItem item = recipe.get().getItemSupplier().get();
            inventory.addItem(item);

            for (int i = 0; i < items.length; i++) {
                InventoryItem it = items[i];
                if (it == null) {
                    continue;
                }

                if (it.getAmount() == 1) {
                    items[i] = null;
                } else {
                    it.decrease();
                }
            }
        }
    }

    /**
     * Renders the 2x2 crafting grid along with the result preview sprite.
     *
     * @param spriteList the list of available sprites
     * @param game       the current game context
     * @return a string builder containing the ANSI-rendered crafting table
     */
    public StringBuilder render(SpriteList spriteList, Game game) {
        var buf = new StringBuilder();

        List<String> sprites = inventory.getSprites(items, spriteList, inventory.getSelectedItemInv() - 29, game);

        Optional<CraftingRecipe> recipe = CraftingRecipeList.getRecipe(Arrays.stream(items)
                .map(item -> item == null ? null : item.getItem().getFirst().getId()).toArray(String[]::new));

        Optional<InventoryItem> craftedItem = recipe.map(craftingRecipe -> craftingRecipe.getItemSupplier().get());

        String[] craftedSprite = craftedItem.map(inventoryItem -> SpriteCombiner.combineTwoSprites(
                inventoryItem.getItem().getFirst().getSpriteState().isPresent()
                        ? spriteList.getSprite(inventoryItem.getItem().getFirst().getSprite())
                                .getSprite(inventoryItem.getItem().getFirst().getSpriteState().get())
                        : spriteList.getSprite(inventoryItem.getItem().getFirst().getSprite()).getSprite(),
                Numbers.getNumberSprite(inventoryItem.getAmount(), game)).split("\n")).orElse(null);

        int counter = 0;
        for (int i = 0; i < ROW_AMOUNT; i++) {
            for (int j = 0; j < 26; j++) {
                if (j == 25) {
                    buf.append("\033[38;5;231;48;5;231m▓".repeat(106));
                } else {
                    for (int k = 0; k < COLUMN_AMOUNT; k++) {
                        buf.append("\033[38;5;231;48;5;231m▓".repeat(2));
                        String sprite = sprites.get(i * 2 + k);
                        if (sprite == null) {
                            buf.append("\033[0m ".repeat(50));
                        } else {
                            String[] spriteLines = sprite.split("\n");
                            buf.append(spriteLines[j]);
                        }
                    }
                    buf.append("\033[38;5;231;48;5;231m▓".repeat(2));
                }

                if (i == 0 && j > 10 || i == 1 && j < 12) {
                    buf.append("\033[0m").append(" ".repeat(7));
                    if (i == 0 && j - 11 == 0 || i == 1 && j == 11) {
                        buf.append("\033[38;5;231;48;5;231m▓".repeat(54));
                    } else {
                        buf.append("\033[38;5;231;48;5;231m▓".repeat(2));
                        if (craftedItem.isEmpty()) {
                            buf.append("\033[0m ".repeat(50));
                        } else {
                            buf.append(craftedSprite[counter]);
                            counter++;
                        }
                        buf.append("\033[38;5;231;48;5;231m▓".repeat(2));
                    }
                }

                buf.append("\n");
            }
        }

        buf.append("\033[0m");

        return buf;
    }

    /**
     * Creates a small crafting table associated with the given inventory.
     *
     * @param inventory the inventory to use for storing crafted items
     */
    public SmallCraftingTable(Inventory inventory) {
        this.inventory = inventory;
    }
}
