package cz.jzitnik.game.threads.list;

import cz.jzitnik.game.Game;
import cz.jzitnik.game.blocks.Chest;
import cz.jzitnik.game.blocks.Furnace;
import cz.jzitnik.game.ui.*;
import cz.jzitnik.tui.MouseHandler;
import cz.jzitnik.tui.ScreenRenderer;
import org.jline.terminal.MouseEvent;
import org.jline.terminal.Terminal;

import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.util.Optional;

import cz.jzitnik.game.annotations.ThreadRegistry;

/**
 * A thread that handles keyboard and mouse input from the terminal.
 * Responsible for routing input events to the appropriate handlers based on the current window.
 */
@ThreadRegistry
public class InputHandlerThread extends Thread {
    private final Game game;
    private final Terminal terminal;
    private final ScreenRenderer screenRenderer;
    private final MouseHandler mouseHandler;

    /**
     * Constructs the input handler thread with required dependencies.
     *
     * @param game           The game instance.
     * @param terminal       The terminal to read input from.
     * @param screenRenderer Renderer to update the game screen.
     */
    public InputHandlerThread(Game game, Terminal terminal, ScreenRenderer screenRenderer) {
        this.game = game;
        this.terminal = terminal;
        this.screenRenderer = screenRenderer;
        this.mouseHandler = new MouseHandler(game, terminal, screenRenderer);
    }

    /**
     * Thread run method that listens for keyboard and mouse events and dispatches them appropriately.
     */
    @Override
    public void run() {
        try {
            while (true) {
                int key = terminal.reader().read();

                if (key == 27) { // ESC
                    key = terminal.reader().read();
                    if (key == '[') {
                        key = terminal.reader().read();
                        if (key == 'M') {
                            MouseEvent mouseEvent = terminal.readMouseEvent();
                            switch (game.getWindow()) {
                                case WORLD -> mouseHandler.handle(mouseEvent);
                                case INVENTORY -> InventoryClickHandler.click(mouseEvent, terminal, screenRenderer,
                                        game, Optional.empty(), Optional.empty());
                                case CRAFTING_TABLE ->
                                        game.getGameStates().craftingTable.click(mouseEvent, terminal, screenRenderer);
                                case CHEST -> ((Chest) game.getWorld()[game.getGameStates().clickY][game
                                        .getGameStates().clickX].stream().filter(i -> i.getBlockId().equals("chest"))
                                        .toList().getFirst().getData()).click(game, mouseEvent, terminal,
                                        screenRenderer);
                                case FURNACE -> ((Furnace) game.getWorld()[game.getGameStates().clickY][game
                                        .getGameStates().clickX].stream().filter(i -> i.getBlockId().equals("furnace"))
                                        .toList().getFirst().getData()).click(game, mouseEvent, terminal,
                                        screenRenderer);
                                case ESC -> game.getGameStates().dependencies.escape.mouse(mouseEvent, terminal,
                                        screenRenderer);
                                case OPTIONS -> game.getGameStates().dependencies.options.handleMouse(mouseEvent,
                                        terminal, screenRenderer);
                                case DEATH_SCREEN -> game.getGameStates().dependencies.deathScreen
                                        .handleMouse(mouseEvent, terminal, screenRenderer, game);
                                case SAVE_EXIT, SAVED -> {
                                }
                            }
                        }
                    }
                }

                switch (key) {
                    case '1', '2', '3', '4', '5', '6', '7', '8', '9' -> game.changeSlot(key - 49, screenRenderer);
                    case 'a' -> new Thread(() -> game.movePlayerLeft(screenRenderer, terminal)).start();
                    case 'd' -> new Thread(() -> game.movePlayerRight(screenRenderer, terminal)).start();
                    case ' ' ->{
                        game.movePlayerUp(screenRenderer);
                        screenRenderer.render(game);
                    }
                    case 'e' -> {
                        if (game.getWindow() != Window.WORLD) {
                            game.getInventory().setSelectedItemInv(-1);
                            CloseHandler.handle(game.getWindow(), game);
                            game.setWindow(Window.WORLD);
                        } else {
                            game.setWindow(Window.INVENTORY);
                        }
                        screenRenderer.render(game);
                    }
                    case 'q' -> {
                        if (game.getWindow() != Window.WORLD) {
                            game.setWindow(Window.WORLD);
                        } else {
                            game.setWindow(Window.ESC);
                            game.getGameStates().dependencies.escape.reset();
                        }
                        screenRenderer.render(game);
                    }
                    default -> {
                    }
                }
            }
        } catch (IOException | BufferUnderflowException e) {
            e.printStackTrace();
        }
    }
}
