package eu.jonahbauer.wizard.server.machine.states;

import eu.jonahbauer.wizard.common.messages.client.ClientMessage;
import eu.jonahbauer.wizard.common.messages.client.CreateSessionMessage;
import eu.jonahbauer.wizard.common.messages.client.JoinSessionMessage;
import eu.jonahbauer.wizard.common.messages.client.RejoinMessage;
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
import eu.jonahbauer.wizard.server.Lobby;
import eu.jonahbauer.wizard.server.NackException;
import eu.jonahbauer.wizard.server.machine.ClientState;
import eu.jonahbauer.wizard.server.machine.Player;
import org.springframework.web.socket.CloseStatus;

import java.util.Optional;

public class LobbyState implements ClientState {
    @Override
    public Optional<ClientState> onEnter(Player player) {
        Lobby.getInstance().join(player);
        return Optional.empty();
    }

    @Override
    public Optional<ClientState> onMessage(Player player, ClientMessage message) {
        if (message instanceof CreateSessionMessage create) {
            Lobby.getInstance().leave(player);
            try {
                var session = Lobby.getInstance().createSession(
                        create.getSessionName(),
                        create.getTimeout(),
                        create.getConfiguration()
                );
                var uuid = session.join(player, create.getPlayerName());
                return Optional.of(new SessionState(session.getUuid(), uuid, create.getPlayerName()));
            } catch (NackException nack) {
                // nack must be sent before joinlobby
                player.send(nack.toMessage());
                Lobby.getInstance().join(player);
                return Optional.empty();
            }
        } else if (message instanceof JoinSessionMessage join) {
            Lobby.getInstance().leave(player);
            try {
                var session = Lobby.getInstance().getSession(join.getSession());
                if (session == null) {
                    throw new NackException(NackMessage.NOT_FOUND, "Session not found.");
                } else {
                    var uuid = session.join(player, join.getPlayerName());
                    return Optional.of(new SessionState(session.getUuid(), uuid, join.getPlayerName()));
                }
            } catch (NackException nack) {
                // nack must be sent before joinlobby
                player.send(nack.toMessage());
                Lobby.getInstance().join(player);
                return Optional.empty();
            }
        } else if (message instanceof RejoinMessage rejoin) {
            Lobby.getInstance().leave(player);
            try {
                var session = Lobby.getInstance().getSession(rejoin.getSession());
                if (session == null) {
                    throw new NackException(NackMessage.NOT_FOUND, "Session not found.");
                } else {
                    var data = session.rejoin(player, rejoin.getPlayer(), rejoin.getSecret());
                    return Optional.of(new SessionState(session.getUuid(), data.getUuid(), data.getName()));
                }
            } catch (NackException nack) {
                // nack must be sent before joinlobby
                player.send(nack.toMessage());
                Lobby.getInstance().join(player);
                return Optional.empty();
            }
        } else {
            return ClientState.super.onMessage(player, message);
        }
    }

    @Override
    public Optional<ClientState> onClose(Player player, CloseStatus status) {
        Lobby.getInstance().leave(player);
        return Optional.of(new Closed());
    }

    @Override
    public void onExit(Player player) {
        Lobby.getInstance().leave(player);
    }
}
