package org.toop.framework.networking.server.handlers;

import org.toop.framework.networking.server.Server;
import org.toop.framework.networking.server.client.Client;
import org.toop.framework.networking.server.client.NettyClient;
import org.toop.framework.networking.server.parsing.ParsedMessage;
import org.toop.framework.utils.Utils;

public class MessageHandler implements Handler<ParsedMessage> {

    private final Server server;
    private final NettyClient client;

    public MessageHandler(Server server, NettyClient client) {
        this.server = server;
        this.client = client;
    }

    @Override
    public void handle(ParsedMessage message) {
        switch (message.command()) {
            case "ping" -> client.send("PONG");
            case "login" -> handleLogin(message, client);
            case "get" -> handleGet(message, client);
            case "subscribe" -> handleSubscribe(message, client);
            case "move" -> handleMove(message, client);
            case "challenge" -> handleChallenge(message, client);
            case "message" -> handleMessage(message, client);
            case "help" -> handleHelp(message, client);
            case "tournament" -> handleTournament(message, client);
            default -> client.send("ERROR Unknown command");
        }
    }

    // DO NOT INVERT
    private boolean hasArgs(String... args) {
        if (args.length < 1) {
            client.send("ERR not enough arguments");
            return false;
        }
        return true;
    }

    private void handleLogin(ParsedMessage p, NettyClient client) {
        if (!hasArgs(p.args())) return;

        client.setName(p.args()[0]);
    }

    private void handleSubscribe(ParsedMessage p, NettyClient client) {
        if (!hasArgs(p.args())) return;

        server.subscribeClient(client.name(), p.args()[0]);
    }

    private void handleHelp(ParsedMessage p, NettyClient client) {
        // TODO
    }

    private void handleMessage(ParsedMessage p, NettyClient client) {
        // TODO
    }

    private void handleGet(ParsedMessage p, NettyClient client) {
        if (!hasArgs(p.args())) return;

        switch (p.args()[0]) {
            case "playerlist" -> {
                var names = server.onlineUsers().stream().map(Client::name).iterator();
                client.send("SVR PLAYERLIST " + Utils.returnQuotedString(names));
            }
            case "gamelist" -> {
                var names = server.gameTypes().stream().iterator();
                client.send("SVR GAMELIST " + Utils.returnQuotedString(names));
            }
            case "admins" -> {
                var names = server.getAdmins().stream().map(Client::name).iterator();
                client.send("SVR ADMINS " + Utils.returnQuotedString(names));
            }
        }
    }

    private void handleChallenge(ParsedMessage p, NettyClient client) {
        if (!hasArgs(p.args())) return;
        if (p.args().length < 2) return;

        if (p.args()[0].equalsIgnoreCase("accept")) {
            try {
                long id = Long.parseLong(p.args()[1]);

                if (id <= 0) {
                    client.send("ERR id must be a positive number");
                    return;
                }

                server.acceptChallenge(id);

            } catch (NumberFormatException e) {
                client.send("ERR id is not a valid number or too big");
                return;
            }
            return;
        }

        server.challengeClient(client.name(), p.args()[0], p.args()[1]);
    }

    private void handleMove(ParsedMessage p, NettyClient client) {
        if(!hasArgs(p.args())) return;

        var player = client.player();
        if (player == null) return;

        // TODO check if not number
        player.setMove(1L << Integer.parseInt(p.args()[0]));
    }

    private void handleTournament(ParsedMessage p, NettyClient client) {
        if(!hasArgs(p.args())) return;

        if (p.args()[0].equalsIgnoreCase("start") && p.args().length > 1) {
            server.startTournament(p.args()[1], client, false); // TODO add shuffle to msg
        }
    }
}
