/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 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.core;

import de.steamwar.Reflection;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.Sound;
import org.bukkit.entity.Player;

import java.util.UUID;

public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper {

    @Override
    public void playPling(Player player) {
        player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1);
    }

    @Override
    public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
        if(type == ChatMessageType.CHAT)
            type = ChatMessageType.SYSTEM;

        player.spigot().sendMessage(type, msg);
    }

    private static final Class<?> dataWatcherObject = Reflection.getClass("net.minecraft.network.syncher.EntityDataAccessor");
    private static final Class<?> dataWatcherRegistry = Reflection.getClass("net.minecraft.network.syncher.EntityDataSerializers");
    private static final Class<?> dataWatcherSerializer = Reflection.getClass("net.minecraft.network.syncher.EntityDataSerializer");
    private static final Reflection.Constructor dataWatcherObjectConstructor = Reflection.getConstructor(dataWatcherObject, int.class, dataWatcherSerializer);
    @Override
    public Object getDataWatcherObject(int index, Class<?> type) {
        return dataWatcherObjectConstructor.invoke(index, Reflection.getField(dataWatcherRegistry, dataWatcherSerializer, 0, type).get(null));
    }

    private static final Class<?> item = Reflection.getClass("net.minecraft.network.syncher.SynchedEntityData$DataItem");
    private static final Reflection.Constructor itemConstructor = Reflection.getConstructor(item, dataWatcherObject, Object.class);
    @Override
    public Object getDataWatcherItem(Object dwo, Object value) {
        return itemConstructor.invoke(dwo, value);
    }

    @Override
    public BountifulWrapper.PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset) {
        Reflection.Field<Double> posX = Reflection.getField(packetClass, double.class, fieldOffset);
        Reflection.Field<Double> posY = Reflection.getField(packetClass, double.class, fieldOffset+1);
        Reflection.Field<Double> posZ = Reflection.getField(packetClass, double.class, fieldOffset+2);
        boolean isByteClass = packetClass.getSimpleName().contains("PacketPlayOutEntityTeleport") || packetClass.getSimpleName().contains("PacketPlayOutNamedEntitySpawn");
        Class<?> pitchYawType = isByteClass ? byte.class : int.class;
        Reflection.Field<?> lookYaw = Reflection.getField(packetClass, pitchYawType, isByteClass ? 0 : 1);
        Reflection.Field<?> lookPitch = Reflection.getField(packetClass, pitchYawType, isByteClass ? 1 : 2);

        return (packet, x, y, z, pitch, yaw) -> {
            posX.set(packet, x);
            posY.set(packet, y);
            posZ.set(packet, z);
            if (isByteClass) {
                lookYaw.set(packet, (byte) (yaw*256/360));
                lookPitch.set(packet, (byte) (pitch*256/360));
            } else {
                lookYaw.set(packet, (int) (yaw*256/360));
                lookPitch.set(packet, (int) (pitch*256/360));
            }
        };
    }

    @Override
    public BountifulWrapper.PositionSetter getRelMoveSetter(Class<?> packetClass) {
        Class<?> type = Core.getVersion() > 12 ? short.class : int.class;
        int fieldOffset = Core.getVersion() > 12 ? 0 : 1;
        Reflection.Field<?> moveX = Reflection.getField(packetClass, type, 0 + fieldOffset);
        Reflection.Field<?> moveY = Reflection.getField(packetClass, type, 1 + fieldOffset);
        Reflection.Field<?> moveZ = Reflection.getField(packetClass, type, 2 + fieldOffset);
        Reflection.Field<Byte> moveYaw = Reflection.getField(packetClass,  byte.class, 0);
        Reflection.Field<Byte> movePitch = Reflection.getField(packetClass, byte.class, 1);

        return (packet, x, y, z, pitch, yaw) -> {
            moveX.set(packet, (short)(x*4096));
            moveY.set(packet, (short)(y*4096));
            moveZ.set(packet, (short)(z*4096));
            moveYaw.set(packet, (byte)(yaw*256/360));
            movePitch.set(packet, (byte)(pitch*256/360));
        };
    }

    @Override
    public BountifulWrapper.UUIDSetter getUUIDSetter(Class<?> packetClass) {
        Reflection.Field<UUID> uuidField = Reflection.getField(packetClass, UUID.class, 0);

        return uuidField::set;
    }
}
