/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2026 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.velocitycore.advancements;

import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.listeners.BasicListener;
import it.unimi.dsi.fastutil.objects.Object2IntMap;

import java.lang.reflect.Field;
import java.util.Optional;

// @Linked
public class AdvancementsManager extends BasicListener {

    private static SelectAdvancementTabPacket selectAdvancementTabPacket;

    static {
        selectAdvancementTabPacket = new SelectAdvancementTabPacket(Optional.of("steamwar:advancements/root"));

        registerPacketId(ProtocolVersion.MINECRAFT_1_21_9, 0x53, 0x80);
        registerPacketId(ProtocolVersion.MINECRAFT_1_21_7, 0x4E, 0x7B);
        registerPacketId(ProtocolVersion.MINECRAFT_1_21_6, 0x4E, 0x7B);
        registerPacketId(ProtocolVersion.MINECRAFT_1_21_5, 0x4E, 0x7B);
        registerPacketId(ProtocolVersion.MINECRAFT_1_21_4, 0x4F, 0x7B);
    }

    private static void registerPacketId(ProtocolVersion version, int selectAdvancementTabPacket, int advancementPacket) {
        try {
            StateRegistry.PacketRegistry.ProtocolRegistry registry = StateRegistry.PLAY.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, version);
            Field field = StateRegistry.PacketRegistry.ProtocolRegistry.class.getDeclaredField("packetClassToId");
            field.setAccessible(true);
            Object2IntMap<Class<? extends MinecraftPacket>> map = (Object2IntMap) field.get(registry);
            map.put(SelectAdvancementTabPacket.class, selectAdvancementTabPacket);
            map.put(Advancement.Packet.class, advancementPacket);
        } catch (Exception e) {
            // Ignore
        }
    }

    @Subscribe(priority = -1000)
    public void onPostLogin(PostLoginEvent event) {
        sendAdvancements(event.getPlayer());
    }

    @Subscribe(priority = -1000)
    public void onServerPostConnect(ServerPostConnectEvent event) {
        sendAdvancements(event.getPlayer());
    }

    private void sendAdvancements(Player player) {
        // Only enable for 1.21.4 or higher
        if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_4)) {
            return;
        }

        ((ConnectedPlayer) player).getConnection().write(selectAdvancementTabPacket);
        SteamwarUser user = SteamwarUser.get(player.getUniqueId());
        for (Advancement advancement : Advancements.getAll()) {
            advancement.get(user).update();
        }
    }

    @Subscribe
    public void onDisconnect(DisconnectEvent event) {
        SteamwarUser user = SteamwarUser.get(event.getPlayer().getUniqueId());
        for (Advancement advancement : Advancements.getAll()) {
            advancement.data.remove(user);
        }
        Advancement.values.remove(user);
    }
}
