package cz.jzitnik.game.blocks;

import cz.jzitnik.game.annotations.BlockBreakAction;
import cz.jzitnik.game.annotations.RightClickLogic;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.Game;
import cz.jzitnik.game.entities.items.InventoryItem;
import cz.jzitnik.game.entities.items.Item;
import cz.jzitnik.game.handlers.rightclick.RightClickHandler;
import cz.jzitnik.game.ui.InventoryClickHandler;
import cz.jzitnik.game.ui.Window;
import cz.jzitnik.tui.ScreenRenderer;
import cz.jzitnik.tui.SpriteList;
import cz.jzitnik.tui.utils.Numbers;
import cz.jzitnik.tui.utils.SpriteCombiner;
import org.jline.terminal.MouseEvent;
import org.jline.terminal.Terminal;

import java.io.Serializable;
import java.util.List;
import java.util.Optional;

@RightClickLogic
public class Furnace implements RightClickHandler, Serializable {
    private Block block;
    private final InventoryItem[] items = new InventoryItem[2];
    private InventoryItem outputItem;
    private int size;
    private boolean smelting;

    private static final int COLUMN_AMOUNT = 3;
    private static final int CELL_WIDTH = 50;
    private static final int CELL_HEIGHT = 27;
    private static final int BORDER_SIZE = 2;

    public Furnace(Block block) {
        this.block = block;
    }

    public Furnace() {}

    public void render(Game game, StringBuilder buffer, Terminal terminal, SpriteList spriteList) {
        int widthPixels = COLUMN_AMOUNT * (CELL_WIDTH + BORDER_SIZE) + BORDER_SIZE;
        var inventory = game.getInventory();
        int moveLeft = Math.max(0, (terminal.getWidth() / 2) - (widthPixels / 2));

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

        String[] outputSprite = outputItem == null ? null
                : SpriteCombiner.combineTwoSprites(
                        outputItem.getItem().getFirst().getSpriteState().isPresent()
                                ? spriteList.getSprite(outputItem.getItem().getFirst().getSprite())
                                        .getSprite(outputItem.getItem().getFirst().getSpriteState().get())
                                : spriteList.getSprite(outputItem.getItem().getFirst().getSprite()).getSprite(),
                        Numbers.getNumberSprite(outputItem.getAmount(), game)).split("\n");

        for (int j = 0; j < CELL_HEIGHT; j++) {
            buffer.append("\033[0m").append(" ".repeat(moveLeft));

            buffer.append("\033[38;5;231;48;5;231m▓".repeat(BORDER_SIZE));
            if (j == 0 || j == CELL_HEIGHT - 1) {
                buffer.append("\033[38;5;231;48;5;231m▓".repeat(CELL_WIDTH));
            } else {
                if (items[0] == null) {
                    buffer.append("\033[0m ".repeat(CELL_WIDTH));
                } else {
                    String sprite = sprites.get(0);
                    String[] spriteLines = sprite.split("\n");
                    buffer.append(spriteLines[j - 1]);
                }
            }
            buffer.append("\033[38;5;231;48;5;231m▓".repeat(BORDER_SIZE));

            buffer.append("\n");
        }

        for (int j = 0; j < CELL_HEIGHT; j++) {
            buffer.append("\033[0m").append(" ".repeat(moveLeft));

            buffer.append("\033[0m").append(" ".repeat(2 * (2 * BORDER_SIZE + CELL_WIDTH)));

            buffer.append("\033[38;5;231;48;5;231m▓".repeat(BORDER_SIZE));
            if (j == 0 || j == CELL_HEIGHT - 1) {
                buffer.append("\033[38;5;231;48;5;231m▓".repeat(CELL_WIDTH));
            } else {
                if (outputItem == null) {
                    buffer.append("\033[0m ".repeat(CELL_WIDTH));
                } else {
                    buffer.append(outputSprite[j - 1]);
                }
            }
            buffer.append("\033[38;5;231;48;5;231m▓".repeat(BORDER_SIZE));
            buffer.append("\n");
        }

        for (int j = 0; j < CELL_HEIGHT; j++) {
            buffer.append("\033[0m").append(" ".repeat(moveLeft));

            buffer.append("\033[38;5;231;48;5;231m▓".repeat(BORDER_SIZE));
            if (j == 0 || j == CELL_HEIGHT - 1) {
                buffer.append("\033[38;5;231;48;5;231m▓".repeat(CELL_WIDTH));
            } else {
                if (items[1] == null) {
                    buffer.append("\033[0m ".repeat(CELL_WIDTH));
                } else {
                    String sprite = sprites.get(1);
                    String[] spriteLines = sprite.split("\n");
                    buffer.append(spriteLines[j - 1]);
                }
            }
            buffer.append("\033[38;5;231;48;5;231m▓".repeat(BORDER_SIZE));

            buffer.append("\n");
        }

        buffer.append("\n".repeat(20));

        size = buffer.toString().split("\n").length;

        game.getInventory().renderFull(buffer, terminal, spriteList, false, Optional.of(size), game);
    }

    public void click(Game game, MouseEvent mouseEvent, Terminal terminal, ScreenRenderer screenRenderer) {
        int x = mouseEvent.getX();
        int y = mouseEvent.getY();
        int widthPixels = COLUMN_AMOUNT * (CELL_WIDTH + BORDER_SIZE) + BORDER_SIZE;
        int moveLeft = Math.max(0, (terminal.getWidth() / 2) - (widthPixels / 2));

        if (x > moveLeft && x <= moveLeft + CELL_WIDTH + BORDER_SIZE && y > 0 && y < CELL_HEIGHT
                && mouseEvent.getType() == MouseEvent.Type.Pressed) {
            InventoryItem selectedItem = game.getInventory().getSelectedItemNo(Optional.of(items));
            if (selectedItem != null && !game.getGameStates().dependencies.smelting.smeltingList.containsKey(selectedItem.getItem().getFirst().getId())) {
                return;
            }

            InventoryClickHandler.handleItemClick(mouseEvent, game.getInventory(), items, 0, 50, Optional.of(items));

            screenRenderer.render(game);
            checkSmelt(game, screenRenderer);
        } else if (x > moveLeft + (2 * (2 * BORDER_SIZE + CELL_WIDTH))
                && x <= moveLeft + (3 * (2 * BORDER_SIZE + CELL_WIDTH)) && y > CELL_HEIGHT && y <= 2 * CELL_HEIGHT
                && mouseEvent.getType() == MouseEvent.Type.Pressed) {
            pickup(game);
            screenRenderer.render(game);
        } else if (x > moveLeft && x <= moveLeft + CELL_WIDTH + BORDER_SIZE && y > 2 * CELL_HEIGHT
                && y < 3 * CELL_HEIGHT && mouseEvent.getType() == MouseEvent.Type.Pressed) {
            InventoryItem selectedItem = game.getInventory().getSelectedItemNo(Optional.of(items));
            if (selectedItem != null && !game.getGameStates().dependencies.smelting.fuelList.containsKey(selectedItem.getItem().getFirst().getId())) {
                return;
            }

            InventoryClickHandler.handleItemClick(mouseEvent, game.getInventory(), items, 1, 50, Optional.of(items));

            screenRenderer.render(game);
            checkSmelt(game, screenRenderer);
        } else {
            InventoryClickHandler.click(mouseEvent, terminal, screenRenderer, game, Optional.of(size + 20),
                    Optional.of(items));
        }
    }

    public void setSmelting(boolean smelting) {
        this.smelting = smelting;
        this.block.setSpriteState(smelting ? cz.jzitnik.game.sprites.Furnace.FurnaceState.ON
                : cz.jzitnik.game.sprites.Furnace.FurnaceState.OFF);
    }

    public void checkSmelt(Game game, ScreenRenderer screenRenderer) {
        if (items[0] == null || items[1] == null) {
            return;
        }

        if (!smelting) {
            startSmelting(game, screenRenderer);
        }
    }

    public void rerender(Game game, ScreenRenderer screenRenderer) {
        if (game.getWindow() == Window.FURNACE) {
            screenRenderer.render(game);
        }
    }

    public void pickup(Game game) {
        if (outputItem == null) {
            return;
        }

        game.getInventory().addItem(outputItem);
        outputItem = null;
    }

    public void startSmelting(Game game, ScreenRenderer screenRenderer) {
        setSmelting(true);

        // Add smelt item
        Thread thread1 = new Thread(() -> {
            do {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                if (smelting) {
                    var supplier = game.getGameStates().dependencies.smelting.smeltingList.get(items[0].getItem().getFirst().getId());
                    if (outputItem == null) {
                        outputItem = new InventoryItem(1, supplier.get());
                    } else {
                        outputItem.add(supplier.get());
                    }

                    items[0].decrease();
                    if (items[0].getAmount() == 0) {
                        items[0] = null;
                    }
                    rerender(game, screenRenderer);
                }

            } while (items[0] != null && smelting);
        });

        Thread thread2 = new Thread(() -> {
            while (true) {
                Item fuel = items[1].getItem().getFirst();
                double smelts = game.getGameStates().dependencies.smelting.fuelList.get(fuel.getId());

                items[1].decrease();
                if (items[1].getAmount() == 0) {
                    items[1] = null;
                }
                rerender(game, screenRenderer);

                try {
                    Thread.sleep((long) (10000 * smelts));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                if (items[0] == null || items[1] == null) {
                    setSmelting(false);
                    rerender(game, screenRenderer);
                    break;
                }

                rerender(game, screenRenderer);
            }
        });

        thread1.start();
        thread2.start();
    }

    @BlockBreakAction("furnace")
    public void breakBlock(Game game) {
        for (var i = 0; i < items.length; i++) {
            if (items[i] == null) {
                continue;
            }

            game.getInventory().addItem(items[i]);
            items[i] = null;
        }

        if (outputItem != null) {
            game.getInventory().addItem(outputItem);
            outputItem = null;
        }

        setSmelting(false);
    }

    @Override
    public void onBlockRightClick(int ignored, int ignored2, Game game, ScreenRenderer ignored3) {
        game.setWindow(Window.FURNACE);
    }
}
