package eu.jonahbauer.wizard.server.machine;

import eu.jonahbauer.wizard.common.machine.Context;
import eu.jonahbauer.wizard.common.messages.client.ClientMessage;
import eu.jonahbauer.wizard.common.messages.server.Response;
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
import eu.jonahbauer.wizard.server.machine.states.CreatedState;
import lombok.SneakyThrows;
import org.jetbrains.annotations.Nullable;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.ArrayList;

public class Player extends Context<ClientState, Player> {
    private final WebSocketSession session;
    private final ArrayList<ServerMessage> buffer = new ArrayList<>();
    private Class<?> shouldBuffer = null;

    public Player(WebSocketSession session) {
        super(new CreatedState());
        this.session = session;
    }

    @Override
    protected void handleError(Throwable t) {

    }

    public void onOpen() {
        execute(s -> s.onOpen(this));
    }

    public void onMessage(ClientMessage message) {
        execute(s -> s.onMessage(this, message));
    }

    public void onClose(CloseStatus status) {
        execute(s -> s.onClose(this, status));
    }

    public void buffer() {
        shouldBuffer = Response.class;
    }

    public void disconnect() {
        disconnect(null);
    }

    public void disconnect(@Nullable String reason) {
        try {
            session.close(new CloseStatus(CloseStatus.GOING_AWAY.getCode(), reason));
        } catch (IOException ignored) {
            // ignored
        }
    }

    @SneakyThrows
    public void send(ServerMessage message) {
        synchronized (session) {
            if (shouldBuffer != null && shouldBuffer.isInstance(message)) {
                session.sendMessage(new TextMessage(message.toString()));
                shouldBuffer = null;
                for (ServerMessage serverMessage : buffer) {
                    session.sendMessage(new TextMessage(serverMessage.toString()));
                }
                buffer.clear();
            } else if (shouldBuffer != null) {
                buffer.add(message);
            } else {
                session.sendMessage(new TextMessage(message.toString()));
            }
        }
    }
}
