package eu.jonahbauer.wizard.client.libgdx.state;

import eu.jonahbauer.wizard.client.libgdx.Client;
import eu.jonahbauer.wizard.client.libgdx.screens.LoadingScreen;
import eu.jonahbauer.wizard.common.messages.observer.ObserverMessage;
import eu.jonahbauer.wizard.common.messages.server.AckMessage;
import eu.jonahbauer.wizard.common.messages.server.GameMessage;
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
import eu.jonahbauer.wizard.common.messages.server.StartingGameMessage;
import eu.jonahbauer.wizard.common.model.Configuration;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;

import java.util.*;

@Log4j2
@RequiredArgsConstructor
public final class AwaitingGameLog extends BaseState {
    private static final int TIMEOUT_MILLIS = 10_000;

    private final UUID self;
    private final UUID session;
    private final String sessionName;
    private final Configuration configuration;

    private final LinkedHashMap<UUID, String> players;

    private final List<ObserverMessage> messages = new ArrayList<>();

    private boolean started = false;

    @Override
    public Optional<ClientState> onEnter(Client client) {
        log.info("Waiting for game log...");
        if (!client.isError()) showScreen(client);
        client.timeout(this, TIMEOUT_MILLIS);
        return Optional.empty();
    }

    @Override
    public Optional<ClientState> onErrorDismissed(Client client) {
        showScreen(client);
        return Optional.empty();
    }

    @Override
    public Optional<ClientState> onMessage(Client client, ServerMessage message) {
        if (!started) {
            if (message instanceof StartingGameMessage) {
                started = true;
                return Optional.empty();
            } else {
                return unexpectedMessage(client, message);
            }
        } else if (message instanceof GameMessage gameMessage) {
            messages.add(gameMessage.getObserverMessage());
            return Optional.empty();
        } else if (message instanceof AckMessage) {
            var game = new Game(self, session, sessionName, configuration, players);
            game.init(messages);
            return Optional.of(game);
        } else {
            return unexpectedMessage(client, message);
        }
    }

    private void showScreen(Client client) {
        client.getGame().setScreen(new LoadingScreen(client.getGame(), "menu.loading.rejoining"));
    }
}
