/*
 *    This file is a part of the SteamWar software.
 *
 *    Copyright (C) 2023  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 de.steamwar.Reflection;
import com.mojang.authlib.GameProfile;
import de.steamwar.core.BountifulWrapper;
import de.steamwar.core.Core;
import de.steamwar.core.FlatteningWrapper;
import de.steamwar.core.ProtocolWrapper;
import lombok.Getter;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;

import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;

@Getter
public class RPlayer extends REntity {

    private static int skinPartsIndex() {
        switch(Core.getVersion()) {
            case 8:
                return 10;
            case 9:
                return 12;
            case 10:
            case 12:
                return 13;
            case 14:
                return 15;
            case 15:
                return 16;
            case 18:
            case 19:
            default:
                return 17;
        }
    }

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

    private final String name;

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

    @Override
    void list(Consumer<Object> packetSink) {
        packetSink.accept(ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.ADD, new GameProfile(uuid, name), 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) {
        packetSink.accept(ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.REMOVE, new GameProfile(uuid, name), GameMode.CREATIVE));
    }

    private static final Class<?> namedSpawnPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundAddPlayerPacket");
    private static final Function<REntity, Object> namedSpawnPacketGenerator = spawnPacketGenerator(namedSpawnPacket, Core.getVersion() == 8 ? 1 : 0);
    private static final Reflection.Field<UUID> namedSpawnUUID = Reflection.getField(namedSpawnPacket, UUID.class, 0);
    private Object getNamedSpawnPacket() {
        Object packet = namedSpawnPacketGenerator.apply(this);
        namedSpawnUUID.set(packet, uuid);
        FlatteningWrapper.impl.setNamedSpawnPacketDataWatcher(packet);
        return packet;
    }
}
