package cz.jzitnik.tui;

import cz.jzitnik.game.Game;
import cz.jzitnik.game.entities.Block;
import cz.jzitnik.game.ui.Window;
import lombok.AllArgsConstructor;
import org.jline.terminal.MouseEvent;
import org.jline.terminal.Terminal;

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

@AllArgsConstructor
public class MouseHandler {
    private Game game;
    private Terminal terminal;
    private ScreenRenderer screenRenderer;

    public void handle(MouseEvent mouseEvent) {
        if (mouseEvent.getButton() == MouseEvent.Button.Button1 && mouseEvent.getType() == MouseEvent.Type.Pressed) {
            leftClick(mouseEvent);
            return;
        }

        if (mouseEvent.getButton() == MouseEvent.Button.Button3 && mouseEvent.getType() == MouseEvent.Type.Pressed) {
            rightClick(mouseEvent);
            return;
        }

        if (mouseEvent.getType() == MouseEvent.Type.Moved) {
            move(mouseEvent);
            return;
        }

        if (mouseEvent.getType() == MouseEvent.Type.Wheel) {
            scroll(mouseEvent);
        }
    }

    private void scroll(MouseEvent mouseEvent) {
        if (game.getWindow() == Window.WORLD) {
            if (mouseEvent.getButton() == MouseEvent.Button.WheelUp) {
                if (game.getInventory().getItemInhHandIndex() == 0) {
                    game.changeSlot(8, screenRenderer);
                } else {
                    game.changeSlot(game.getInventory().getItemInhHandIndex() - 1, screenRenderer);
                }
            }

            if (mouseEvent.getButton() == MouseEvent.Button.WheelDown) {
                if (game.getInventory().getItemInhHandIndex() == 8) {
                    game.changeSlot(0, screenRenderer);
                } else {
                    game.changeSlot(game.getInventory().getItemInhHandIndex() + 1, screenRenderer);
                }
            }
        }
    }

    private void leftClick(MouseEvent mouseEvent) {
        int mouseX = mouseEvent.getX();
        int mouseY = mouseEvent.getY();

        int[] cords = game.getPlayerCords();
        if (cords == null)
            return;

        int playerX = cords[0];
        int playerY = cords[1];

        int[] data = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(),
                terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);

        int startX = data[0];
        int startY = data[2];

        int blockX = startX + (mouseX / 50); // 50 chars wide per sprite
        int blockY = startY + (mouseY / 25); // 25 lines high per sprite

        if (game.isHitable(blockX, blockY, terminal)) {
            game.hit(screenRenderer, blockX, blockY);
        }

        if (game.isMineable(blockX, blockY, terminal)) {
            screenRenderer.setSelectedBlock(Optional.empty());
            game.mine(screenRenderer, blockX, blockY);
        }
    }

    private void rightClick(MouseEvent mouseEvent) {
        int mouseX = mouseEvent.getX();
        int mouseY = mouseEvent.getY();

        int[] cords = game.getPlayerCords();
        if (cords == null)
            return;

        int playerX = cords[0];
        int playerY = cords[1];

        int[] data = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(),
                terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);

        int startX = data[0];
        int startY = data[2];

        int blockX = startX + (mouseX / 50); // 50 chars wide per sprite
        int blockY = startY + (mouseY / 25); // 25 lines high per sprite

        game.build(blockX, blockY, screenRenderer);
    }

    private void move(MouseEvent mouseEvent) {
        if (game.isMining() || game.getWindow() != Window.WORLD) {
            return;
        }

        int mouseX = mouseEvent.getX();
        int mouseY = mouseEvent.getY();

        int[] cords = game.getPlayerCords();
        if (cords == null)
            return;

        int playerX = cords[0];
        int playerY = cords[1];

        int[] data = ScreenMovingCalculationProvider.calculate(playerX, playerY, terminal.getHeight(),
                terminal.getWidth(), game.getWorld()[0].length, game.getWorld().length);

        int startX = data[0];
        int startY = data[2];

        int blockX = startX + (mouseX / 50); // 50 chars wide per sprite
        int blockY = startY + (mouseY / 25); // 25 lines high per sprite

        if (blockY == playerX && blockY == playerY) {
            return;
        }

        if (game.isMineable(blockX, blockY, terminal)) {
            List<Integer> list = new ArrayList<>();
            list.add(blockX);
            list.add(blockY);

            if (screenRenderer.getSelectedBlock().isPresent()
                    && screenRenderer.getSelectedBlock().get().get(0).equals(blockX)
                    && screenRenderer.getSelectedBlock().get().get(1).equals(blockY)) {
                return;
            }

            screenRenderer.setSelectedBlock(Optional.of(list));
        } else {
            if (screenRenderer.getSelectedBlock().isEmpty()) {
                return;
            }
            screenRenderer.setSelectedBlock(Optional.empty());
        }

        screenRenderer.render(game);
    }
}