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

package pp.battleship.game.client;

import pp.battleship.message.server.EffectMessage;
import pp.battleship.message.server.GameDetails;
import pp.battleship.message.server.StartBattleMessage;
import pp.battleship.model.IntPoint;

import java.io.File;
import java.io.IOException;
import java.lang.System.Logger.Level;

/**
 * Defines the behavior and state transitions for the client-side game logic.
 * Different states of the game logic implement this interface to handle various game events and actions.
 */
abstract class ClientState {
    /**
     * The game logic object.
     */
    final ClientGameLogic logic;

    /**
     * Constructs a client state of the specified game logic.
     *
     * @param logic the game logic
     */
    ClientState(ClientGameLogic logic) {
        this.logic = logic;
    }

    /**
     * Method to be overridden by subclasses for post-transition initialization.
     * By default, it does nothing, but it can be overridden in derived states.
     */
    void entry() {
        // Default implementation does nothing
    }

    /**
     * Returns the name of the current state.
     *
     * @return the name of the current state
     */
    String getName() {
        return getClass().getSimpleName();
    }

    /**
     * Checks if the editor should be shown.
     *
     * @return true if the editor should be shown, false otherwise
     */
    boolean showEditor() {
        return false;
    }

    /**
     * Checks if the battle state should be shown.
     *
     * @return true if the battle state should be shown, false otherwise
     */
    boolean showBattle() {
        return false;
    }

    /**
     * Checks if the player's map is complete (i.e., all ships are placed).
     *
     * @return true if all ships are placed, false otherwise
     */
    boolean isMapComplete() {
        return false;
    }

    /**
     * Checks if there is currently a preview ship.
     *
     * @return true if there is currently a preview ship, false otherwise
     */
    boolean movingShip() {
        return false;
    }

    /**
     * Handles a click on the player's own map.
     *
     * @param pos the position where the click occurred
     */
    void clickOwnMap(IntPoint pos) {
        ClientGameLogic.LOGGER.log(Level.DEBUG, "clickOwnMap has no effect in {0}", getName()); //NON-NLS
    }

    /**
     * Handles a click on the harbor map.
     *
     * @param pos the position where the click occurred
     */
    void clickHarbor(IntPoint pos) {
        ClientGameLogic.LOGGER.log(Level.DEBUG, "clickHarbor has no effect in {0}", getName()); //NON-NLS
    }

    /**
     * Handles a click on the opponent's map.
     *
     * @param pos the position where the click occurred
     */
    void clickOpponentMap(IntPoint pos) {
        ClientGameLogic.LOGGER.log(Level.DEBUG, "clickOpponentMap has no effect in {0}", getName()); //NON-NLS
    }

    /**
     * Moves the preview ship to the specified position.
     *
     * @param pos the new position for the preview ship
     */
    void movePreview(IntPoint pos) {
        ClientGameLogic.LOGGER.log(Level.DEBUG, "movePreview has no effect in {0}", getName()); //NON-NLS
    }

    /**
     * Rotates the preview ship.
     */
    void rotateShip() {
        ClientGameLogic.LOGGER.log(Level.DEBUG, "rotateShip has no effect in {0}", getName()); //NON-NLS
    }

    /**
     * The user has marked the map as finished.
     */
    void mapFinished() {
        ClientGameLogic.LOGGER.log(Level.ERROR, "mapFinished not allowed in {0}", getName()); //NON-NLS
    }

    /**
     * Sets the game details provided by the server.
     *
     * @param details the game details including map size and ships
     */
    void receivedGameDetails(GameDetails details) {
        ClientGameLogic.LOGGER.log(Level.ERROR, "receivedGameDetails not allowed in {0}", getName()); //NON-NLS
    }

    /**
     * Starts the battle based on the server message.
     *
     * @param msg the message indicating whose turn it is to shoot
     */
    void receivedStartBattle(StartBattleMessage msg) {
        ClientGameLogic.LOGGER.log(Level.ERROR, "receivedStartBattle not allowed in {0}", getName()); //NON-NLS
    }

    /**
     * Reports the effect of a shot based on the server message.
     *
     * @param msg the message containing the effect of the shot
     */
    void receivedEffect(EffectMessage msg) {
        ClientGameLogic.LOGGER.log(Level.ERROR, "receivedEffect not allowed in {0}", getName()); //NON-NLS
    }

    /**
     * Loads a map from the specified file.
     *
     * @param file the file to load the map from
     * @throws IOException if the map cannot be loaded in the current state
     */
    void loadMap(File file) throws IOException {
        throw new IOException("You are not allowed to load a map in this state of the game");
    }

    /**
     * Checks if the own map may be loaded from file.
     *
     * @return true if the own map may be loaded from file, false otherwise
     */
    boolean mayLoadMap() {
        return false;
    }

    /**
     * Checks if the own map may be saved to file.
     *
     * @return true if the own map may be saved to file, false otherwise
     */
    boolean maySaveMap() {
        return true;
    }

    /**
     * Called once per frame by the update loop if this state is active.
     *
     * @param delta time in seconds since the last update call
     */
    void update(float delta) { /* do nothing by default */ }
}
