////////////////////////////////////////
// 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.client.ShootMessage;
import pp.battleship.message.server.EffectMessage;
import pp.battleship.model.IntPoint;
import pp.battleship.model.ShipMap;
import pp.battleship.notification.Sound;

import java.lang.System.Logger.Level;

/**
 * Represents the state of the client where players take turns to attack each other's ships.
 */
class BattleState extends ClientState {
    private boolean myTurn;

    /**
     * Constructs a new instance of {@link BattleState}.
     *
     * @param logic  the game logic
     * @param myTurn true if it is my turn
     */
    public BattleState(ClientGameLogic logic, boolean myTurn) {
        super(logic);
        this.myTurn = myTurn;
    }

    @Override
    public boolean showBattle() {
        return true;
    }

    @Override
    public void clickOpponentMap(IntPoint pos) {
        if (!myTurn)
            logic.setInfoText("wait.its.not.your.turn");
        else if (logic.getOpponentMap().isValid(pos))
            logic.send(new ShootMessage(pos));
    }

    /**
     * Reports the effect of a shot based on the server message.
     *
     * @param msg the message containing the effect of the shot
     */
    //tODO
    @Override
    public void receivedEffect(EffectMessage msg) {
        ClientGameLogic.LOGGER.log(Level.INFO, "report effect: {0}", msg); //NON-NLS
        playSound(msg);
        myTurn = msg.isMyTurn(); //boolean, describes whether it is my turn
        logic.setInfoText(msg.getInfoTextKey()); //
        affectedMap(msg).add(msg.getShot());
        if (destroyedOpponentShip(msg)) {
            logic.getOpponentMap().add(msg.getDestroyedShip());
        }
        if (msg.isGameOver()) {
            //msg.getRemainingOpponentShips().forEach(logic.getOwnMap()::add);
            msg.getRemainingOpponentShips().forEach(logic.getOpponentMap()::add);
            logic.setState(new GameOverState(logic));
        }
    }

    /**
     * Determines which map (own or opponent's) should be affected by the shot based on the message.
     *
     * @param msg the effect message received from the server
     * @return the map (either the opponent's or player's own map) that is affected by the shot
     */
    private ShipMap affectedMap(EffectMessage msg) {
        return msg.isOwnShot() ? logic.getOpponentMap() : logic.getOwnMap();
    }

    /**
     * Checks if the opponent's ship was destroyed by the player's shot.
     *
     * @param msg the effect message received from the server
     * @return true if the shot destroyed an opponent's ship, false otherwise
     */
    private boolean destroyedOpponentShip(EffectMessage msg) {
        return msg.getDestroyedShip() != null && msg.isOwnShot();
    }

    /**
     * Plays a sound based on the outcome of the shot. Different sounds are played for a miss, hit,
     * or destruction of a ship.
     *
     * @param msg the effect message containing the result of the shot
     */
    private void playSound(EffectMessage msg) {
        if (!msg.getShot().isHit())
            logic.playSound(Sound.SPLASH);
        else if (msg.getDestroyedShip() == null)
            logic.playSound(Sound.EXPLOSION);
        else
            logic.playSound(Sound.DESTROYED_SHIP);
    }
}
