package eu.jonahbauer.wizard.core.states;

import eu.jonahbauer.wizard.common.messages.observer.TimeoutMessage;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.messages.player.ContinueMessage;
import eu.jonahbauer.wizard.common.messages.player.PlayerMessage;
import eu.jonahbauer.wizard.core.Game;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;

import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Action.SYNC;
import static eu.jonahbauer.wizard.core.states.GameData.PLAYERS;

public final class SyncState extends GameState implements TransientState {
    private final transient Set<UUID> ready = new HashSet<>();
    private final Function<GameData, GameState> nextState;

    public SyncState(GameData data, Function<GameData, GameState> nextState) {
        super(data.keepAll());
        this.nextState = nextState;
    }

    @Override
    public Optional<GameState> onEnter(Game game) {
        game.notify(new UserInputMessage(null, SYNC, getSyncTimeout(game, true)));
        return syncTimeout(game);
    }

    @Override
    public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
        if (message instanceof ContinueMessage) {
            ready.add(player);

            if (ready.size() == get(PLAYERS).size()) {
                return Optional.of(nextState.apply(getData()));
            } else {
                return Optional.empty();
            }
        } else {
            return super.onMessage(game, player, message);
        }
    }

    @Override
    public Optional<GameState> onTimeout(Game game) {
        game.notify(new TimeoutMessage());
        return Optional.of(nextState.apply(getData()));
    }
}
