package eu.oschl.gui;

import eu.oschl.gui.actions.*;
import eu.oschl.gui.exceptions.InvalidActionId;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.text.TextFlow;

import java.util.ArrayList;

public class GameController implements Observer {
    @FXML
    private TextFlow output;

    @FXML
    private VBox inputButtonContainer;

    @FXML
    private VBox inventoryContainer;

    @FXML
    public void initialize() {
        Output.setOutputElement(output);
        Session.getActionProcessor().register(this);
        update();

        Output.print(Session.getGame().getPrologue());
    }

    @FXML
    private void exectuteAction(ActionEvent event) throws InvalidActionId {
        Button clickedButton = (Button) event.getSource();
        ButtonData buttonData = (ButtonData) clickedButton.getUserData();

        var actionProcessor = Session.getActionProcessor();

        actionProcessor.executeAction(buttonData.actionId(), buttonData.arguments());
    }

    @Override
    public void update() {
        if (!Session.getGame().isRunning()) {
            finishGame();
            return;
        }

        renderActionButtons();
        renderInventoryItems();
    }

    private void renderActionButtons() {
        inputButtonContainer.getChildren().clear();

        var newButtons = new ArrayList<Button>();

        for (Action action : Session.getActionProcessor().getActions()) {
            switch (action) {
                case Enter enter -> {
                    var room = Session.getGame().getCurrentRoom();
                    var passages = room.getPassages();

                    for (var passage : passages) {
                        var lastPassage = Session.getGame().getLastPassage();

                        if (!Session.getGame().getCurrentRoom().isExplored() && (lastPassage.isEmpty() || passage != lastPassage.get())) {
                            continue;
                        }

                        var label = passage.isSeeThrough() || passage.getOtherRoom(room).wasEntered()
                                ? enter.getName() + " " + passage.getName() + " (>> " + passage.getOtherRoom(Session.getGame().getCurrentRoom()).getName() + ")"
                                : enter.getName() + " " + passage.getName() + " (>> ???)";
                        var buttonData = new ButtonData(enter.getId(), passage.getName());

                        var button = createActionButton(label, buttonData);

                        button.getStyleClass().add("enter-button");

                        newButtons.add(button);
                    }
                }
                case PressButton pressButton -> {
                    if (!Session.getGame().getCurrentRoom().isExplored()) {
                        continue;
                    }

                    if (Session.getGame().getCurrentRoom().isBlockedByEnemy()) {
                        continue;
                    }

                    var objects = Session.getGame().getCurrentRoom().getObjects();

                    for (var object : objects) {
                        if (object instanceof eu.oschl.textadventure.objects.Button) {
                            var label = pressButton.getName() + " " + object.getName();
                            var buttonData = new ButtonData(pressButton.getId(), object.getName());

                            var button = createActionButton(label, buttonData);

                            button.getStyleClass().add("press-button");

                            newButtons.add(button);
                        }
                    }
                }
                case Slay slay -> {
                    if (!Session.getGame().getCurrentRoom().isExplored()) {
                        continue;
                    }

                    var enemy = Session.getGame().getCurrentRoom().getEnemy();

                    if (enemy.isPresent() && enemy.get().isAlive()) {
                        var label = slay.getName() + " " + enemy.get().getName();
                        var buttonData = new ButtonData(slay.getId(), enemy.get().getName());

                        var button = createActionButton(label, buttonData);

                        button.getStyleClass().add("slay-button");

                        newButtons.add(button);
                    }
                }
                case TakeItem takeItem -> {
                    if (!Session.getGame().getCurrentRoom().isExplored()) {
                        continue;
                    }

                    if (Session.getGame().getCurrentRoom().isBlockedByEnemy()) {
                        continue;
                    }

                    var objects = Session.getGame().getCurrentRoom().getObjects();

                    for (var object : objects) {
                        if (object instanceof eu.oschl.textadventure.objects.PickableObject) {
                            var label = takeItem.getName() + " " + object.getName();
                            var buttonData = new ButtonData(takeItem.getId(), object.getName());

                            var button = createActionButton(label, buttonData);

                            button.getStyleClass().add("take-button");

                            newButtons.add(button);
                        }
                    }
                }
                case UseItem _ -> {
                }
                default -> newButtons.add(createActionButton(action.getName(), new ButtonData(action.getId())));
            }
        }

        inputButtonContainer.getChildren().addAll(newButtons);
    }

    private void renderInventoryItems() {
        inventoryContainer.getChildren().clear();

        var newItems = new ArrayList<Button>();

        for (var item : Session.getGame().getInventory().getItems()) {
            var label = item.getName();
            var buttonData = new ButtonData("useitem", item.getName());

            var button = createActionButton(label, buttonData);
            button.getStyleClass().add("inventory-item");

            newItems.add(button);
        }

        if (Session.getGame().getInventory().getWeapon().isPresent()) {
            var weapon = Session.getGame().getInventory().getWeapon().get();

            var button = createActionButton(weapon.getName(), new ButtonData(""));
            button.getStyleClass().add("inventory-item");
            button.getStyleClass().add("weapon");
            button.setDisable(true);

            newItems.add(button);
        }

        inventoryContainer.getChildren().addAll(newItems);
    }

    private Button createActionButton(String label, ButtonData buttonData) {
        Button actionButton = new Button(label);

        actionButton.setUserData(buttonData);
        actionButton.setOnAction(this::exectuteAction);
        actionButton.setMaxWidth(Double.MAX_VALUE);

        return actionButton;
    }

    private void finishGame() {
        inputButtonContainer.getChildren().clear();
        inventoryContainer.getChildren().clear();

        Output.printLine();
        Output.printLine();
        Output.print(Session.getGame().getEpilogue());
    }
}
