package de.teleportsuite.bungeemessaging;

import de.teleportsuite.TeleportSuite;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;

import java.io.*;

/**
 * Handles BungeeCord Plugin Messaging.
 * Sends players to other servers and transmits target coordinates
 * so a receiving TeleportSuite instance can teleport them on arrival.
 *
 * Channel "teleportsuite:tp" payload format (DataOutputStream):
 *   String  targetPlayer
 *   String  world
 *   Double  x, y, z
 *   Float   yaw, pitch
 */
public class BungeeMessenger implements PluginMessageListener {

    private static final String BUNGEE_CHANNEL = "BungeeCord";
    private static final String TS_CHANNEL     = "teleportsuite:tp";
    private final TeleportSuite plugin;

    public BungeeMessenger(TeleportSuite plugin) { this.plugin = plugin; }

    public void register() {
        plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, BUNGEE_CHANNEL);
        plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, TS_CHANNEL);
        plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, TS_CHANNEL, this);
    }

    public void unregister() {
        plugin.getServer().getMessenger().unregisterOutgoingPluginChannel(plugin);
        plugin.getServer().getMessenger().unregisterIncomingPluginChannel(plugin);
    }

    /**
     * Connect a player to another BungeeCord server.
     * Also sends a plugin message so the target server knows where to teleport the player.
     */
    public void connectToServer(Player player, String server, String world, double x, double y, double z, float yaw, float pitch) {
        // 1) Notify the target server about the pending teleport
        sendTeleportPayload(player, player.getName(), server, world, x, y, z, yaw, pitch);

        // 2) Switch server via BungeeCord
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             DataOutputStream out = new DataOutputStream(bos)) {
            out.writeUTF("Connect");
            out.writeUTF(server);
            player.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray());
        } catch (IOException e) {
            plugin.getLogger().warning("BungeeCord Connect Fehler: " + e.getMessage());
        }
    }

    private void sendTeleportPayload(Player sender, String targetPlayer, String server, String world,
                                     double x, double y, double z, float yaw, float pitch) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             DataOutputStream out = new DataOutputStream(bos)) {
            out.writeUTF("Forward");
            out.writeUTF(server);
            out.writeUTF(TS_CHANNEL);
            // Sub-payload
            ByteArrayOutputStream sub = new ByteArrayOutputStream();
            DataOutputStream subOut = new DataOutputStream(sub);
            subOut.writeUTF(targetPlayer);
            subOut.writeUTF(world);
            subOut.writeDouble(x);
            subOut.writeDouble(y);
            subOut.writeDouble(z);
            subOut.writeFloat(yaw);
            subOut.writeFloat(pitch);
            byte[] subBytes = sub.toByteArray();
            out.writeShort(subBytes.length);
            out.write(subBytes);
            sender.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray());
        } catch (IOException e) {
            plugin.getLogger().warning("TS Forward Fehler: " + e.getMessage());
        }
    }

    @Override
    public void onPluginMessageReceived(String channel, Player player, byte[] message) {
        if (!channel.equals(TS_CHANNEL)) return;
        try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) {
            String targetName = in.readUTF();
            String world = in.readUTF();
            double x = in.readDouble(), y = in.readDouble(), z = in.readDouble();
            float yaw = in.readFloat(), pitch = in.readFloat();

            plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
                Player target = plugin.getServer().getPlayer(targetName);
                if (target == null || !target.isOnline()) return;
                de.teleportsuite.models.TeleportLocation loc =
                    new de.teleportsuite.models.TeleportLocation(world, x, y, z, yaw, pitch,
                        plugin.getConfigManager().getServerName());
                plugin.getTeleportManager().teleport(target, loc, false);
            }, 20L);
        } catch (IOException e) {
            plugin.getLogger().warning("Fehler beim Lesen der TS-Nachricht: " + e.getMessage());
        }
    }
}
