/*
 *   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.entity;

import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import de.steamwar.core.BountifulWrapper;
import de.steamwar.core.ProtocolWrapper;
import de.steamwar.network.CoreNetworkHandler;
import de.steamwar.network.NetworkSender;
import de.steamwar.network.packets.common.PlayerSkinRequestPacket;
import lombok.Getter;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.world.phys.Vec3;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;

public class RPlayer extends REntity {

    private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(17, Byte.class);

    @Getter
    private final UUID actualUUID;
    @Getter
    private final String name;

    public RPlayer(REntityServer server, UUID uuid, String name, Location location) {
        super(server, EntityType.PLAYER, UUID.nameUUIDFromBytes(uuid.toString().getBytes(StandardCharsets.UTF_8)), location, 0);
        this.actualUUID = uuid;
        this.name = name;
        server.addEntity(this);
    }

    private GameProfile getGameProfile() {
        Property skinData = CoreNetworkHandler.SKIN_DATA_PROMISES.computeIfAbsent(actualUUID, __ -> {
            NetworkSender.sendOrQueue(new PlayerSkinRequestPacket(actualUUID));
            return new Property("textures", null, null);
        });
        if (skinData.value() != null) {
            GameProfile gameProfile = new GameProfile(uuid, name);
            gameProfile.getProperties().put("textures", skinData);
            return gameProfile;
        } else {
            return new GameProfile(uuid, name);
        }
    }

    private GameProfile saved;

    @Override
    void list(Consumer<Object> packetSink) {
        saved = getGameProfile();
        packetSink.accept(ProtocolWrapper.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.ADD, saved, GameMode.CREATIVE));
    }

    @Override
    void spawn(Consumer<Object> packetSink) {
        packetSink.accept(getNamedSpawnPacket());
        packetSink.accept(getDataWatcherPacket(skinPartsDataWatcher, (byte) 0x7F));

        for (Map.Entry<Object, ItemStack> entry : itemSlots.entrySet()) {
            packetSink.accept(getEquipmentPacket(entry.getKey(), entry.getValue()));
        }

        postSpawn(packetSink);
    }

    @Override
    void delist(Consumer<Object> packetSink) {
        if (saved == null) saved = getGameProfile();
        packetSink.accept(ProtocolWrapper.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.REMOVE, saved, GameMode.CREATIVE));
    }

    private Object getNamedSpawnPacket() {
        return new ClientboundAddEntityPacket(
                entityId,
                uuid,
                x,
                y,
                z,
                yaw,
                pitch,
                net.minecraft.world.entity.EntityType.PLAYER,
                0,
                Vec3.ZERO,
                headYaw
        );
    }
}
