package org.toop.framework.game.gameThreads;

import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.gameFramework.model.game.threadBehaviour.AbstractThreadBehaviour;
import org.toop.framework.gameFramework.view.GUIEvents;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.game.threadBehaviour.SupportsOnlinePlay;
import org.toop.framework.gameFramework.model.player.Player;
import org.toop.framework.game.players.OnlinePlayer;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Handles online multiplayer game logic.
 * <p>
 * Reacts to server events, sending moves and updating the game state
 * for the local player while receiving moves from other players.
 */
public class OnlineThreadBehaviour extends AbstractThreadBehaviour implements SupportsOnlinePlay {

    private ExecutorService moveExecutor = Executors.newSingleThreadExecutor();

    /**
     * Creates behaviour and sets the first local player
     * (non-online player) from the given array.
     */
    public OnlineThreadBehaviour(TurnBasedGame game) {
        super(game);
    }

    /** Finds the first non-online player in the array. */
    private int getFirstNotOnlinePlayer(Player[] players) {
        for (int i = 0; i < players.length; i++) {
            if (!(players[i] instanceof OnlinePlayer)) {
                return i;
            }
        }
        throw new RuntimeException("All players are online players");
    }

    /** Starts processing network events for the local player. */
    @Override
    public void start() {
        isRunning.set(true);
    }

    /** Stops processing network events. */
    @Override
    public void stop() {
        isRunning.set(false);
    }

    /**
     * Called when the server notifies that it is the local player's turn.
     * Sends the generated move back to the server.
     */
    @Override
    public void onYourTurn(long clientId) {
        logger.info("Yourturn");
        if (!isRunning.get()) {
            logger.warn("Game is not running!");
            return;
        }

        TurnBasedGame gameCopy = game.deepCopy();
        if (gameCopy == null) {
            logger.error("Could not deep copy game");
            return;
        }
        logger.info("Successfully collected game copy");

        Player player = gameCopy.getPlayer(game.getCurrentTurn());
        if (player == null) {
            logger.error("Could not find current turn's player");
            return;
        }
        logger.info("Successfully collected current turn's player");

        long move = player.getMove(gameCopy);
        logger.info("Move set: {}", move);
        logger.info("Completed onYourTurn");

        sendMove(clientId, move);
    }

    /**
     * Handles a move received from the server for any player.
     * Updates the game state and triggers a UI refresh.
     */
    public void onMoveReceived(long move) {
        if (!isRunning.get()) return;
        game.play(move);

        updateUI();
    }

    /**
     * Handles the end of the game as notified by the server.
     * Updates the UI to show a win or draw result for the local player.
     */
    public void gameFinished(String condition) {
        switch(condition.toUpperCase()){
            case "WIN", "LOSS" -> new EventFlow().addPostEvent(GUIEvents.GameEnded.class, true, game.getWinner()).postEvent();
            case "DRAW" -> new EventFlow().addPostEvent(GUIEvents.GameEnded.class, false, -1).postEvent();
            default -> {
                logger.error("Invalid condition");
                throw new RuntimeException("Unknown condition");
            }
        }
    }
}
