////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////

package pp.battleship.game.singlemode;

import pp.battleship.game.client.BattleshipClient;
import pp.battleship.game.client.ClientGameLogic;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.message.server.GameDetails;
import pp.battleship.message.server.ServerInterpreter;
import pp.battleship.message.server.ServerMessage;
import pp.battleship.message.server.StartBattleMessage;

import java.io.IOException;

/**
 * A proxy class that interprets messages from the server and forwards them to the BattleshipClient.
 * Implements the ServerInterpreter interface to handle specific server messages.
 */
class InterpreterProxy implements ServerInterpreter {
    private final BattleshipClient playerClient;

    /**
     * Constructs an InterpreterProxy with the specified BattleshipClient.
     *
     * @param playerClient the client to which the server messages are forwarded
     */
    InterpreterProxy(BattleshipClient playerClient) {
        this.playerClient = playerClient;
    }

    /**
     * Handles the received GameDetails message by accepting it with the client's game logic.
     * If the client's own map option is set, it also loads the map.
     *
     * @param msg the GameDetails message received from the server
     */
    @Override
    public void received(GameDetails msg) {
        msg.accept(playerClient.getGameLogic());
        if (playerClient.getConfig().getOwnMap() != null)
            playerClient.enqueue(this::loadMap);
    }

    /**
     * Loads the map specified in the client's options and notifies the game logic that the map is finished.
     *
     * @throws RuntimeException if the map fails to load.
     */
    private void loadMap() {
        final ClientGameLogic clientGameLogic = playerClient.getGameLogic();
        try {
            clientGameLogic.loadMap(playerClient.getConfig().getOwnMap());
        }
        catch (IOException e) {
            throw new RuntimeException("Failed to load PlayerClient map", e);
        }
        clientGameLogic.mapFinished();
    }

    /**
     * Forwards the received StartBattleMessage to the client's game logic.
     *
     * @param msg the StartBattleMessage received from the server
     */
    @Override
    public void received(StartBattleMessage msg) {
        forward(msg);
    }

    /**
     * Forwards the received EffectMessage to the client's game logic.
     *
     * @param msg the EffectMessage received from the server
     */
    @Override
    public void received(EffectMessage msg) {
        forward(msg);
    }

    /**
     * Forwards the specified ServerMessage to the client's game logic by enqueuing the message acceptance.
     *
     * @param msg the ServerMessage to forward
     */
    private void forward(ServerMessage msg) {
        playerClient.enqueue(() -> msg.accept(playerClient.getGameLogic()));
    }
}
