package xyz.illuc.neuralgiacore.entities;

import net.adinvas.prototype_pain.PlayerHealthProvider;
import net.adinvas.prototype_pain.limbs.PlayerHealthData;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
import xyz.illuc.neuralgiacore.NeuralgiaCoreMod;

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

public class OfflinePlayerEntity extends LivingEntity {

    private static final EntityDataAccessor<Optional<UUID>> DATA_PLAYER_UUID =
            SynchedEntityData.defineId(OfflinePlayerEntity.class, EntityDataSerializers.OPTIONAL_UUID);
    private static final EntityDataAccessor<String> DATA_PLAYER_NAME =
            SynchedEntityData.defineId(OfflinePlayerEntity.class, EntityDataSerializers.STRING);
    private static final EntityDataAccessor<Byte> DATA_PLAYER_MODE_CUSTOMISATION =
            SynchedEntityData.defineId(OfflinePlayerEntity.class, EntityDataSerializers.BYTE);

    private static final EntityDataAccessor<CompoundTag> DATA_PLAYER_HEALTH =
            SynchedEntityData.defineId(OfflinePlayerEntity.class, EntityDataSerializers.COMPOUND_TAG);

    public OfflinePlayerEntity(EntityType<? extends LivingEntity> entityType, Level level) {
        super(entityType, level);
        setPose(Pose.SLEEPING);
    }

    public OfflinePlayerEntity(Level level) {
        this(NeuralgiaCoreMod.GHOST.get(), level);
    }

    public static OfflinePlayerEntity createFromPlayer(Player player) {
        OfflinePlayerEntity offlinePlayer = NeuralgiaCoreMod.GHOST.get().create(player.level());
        offlinePlayer.setPlayerName(player.getName().getString());
        offlinePlayer.setPlayerUUID(player.getUUID());


        offlinePlayer.setPos(player.getX(), player.getY(), player.getZ());
        offlinePlayer.setYBodyRot(player.getYRot());
        offlinePlayer.yRotO = player.yRotO;
        offlinePlayer.setXRot(player.getXRot());
        offlinePlayer.xRotO = player.xRotO;
        offlinePlayer.yHeadRot = player.yHeadRot;
        offlinePlayer.yHeadRotO = player.yHeadRotO;
        offlinePlayer.setHealth(player.getHealth());
        offlinePlayer.setSecondsOnFire(player.getRemainingFireTicks());

        player.getCapability(PlayerHealthProvider.PLAYER_HEALTH_DATA).ifPresent(
                ph -> {
                    offlinePlayer.setPlayerHealthData(ph);
                }
        );


        try {
            Field dataPlayerModeCustomization = ObfuscationReflectionHelper.findField(Player.class, "f_36089_");
            offlinePlayer.setModelCustomisation(player.getEntityData().get((EntityDataAccessor<Byte>) dataPlayerModeCustomization.get(null)));
        } catch (Exception e) {

        }

        return offlinePlayer;
    }

    public void toPlayer(ServerPlayer player) {
        player.setHealth(getHealth());
        player.setAirSupply(getAirSupply());
        player.setSecondsOnFire(getRemainingFireTicks());
        getActiveEffects().forEach(player::addEffect);
        player.teleportTo(getX(), getY(), getZ());
        player.yRotO = yRotO;
        player.xRotO = xRotO;
        player.yHeadRot = yHeadRot;
        player.yHeadRotO = yHeadRotO;
        player.getCapability(PlayerHealthProvider.PLAYER_HEALTH_DATA).ifPresent(
                ph -> {

                    ph.deserializeNBT(this.entityData.get(DATA_PLAYER_HEALTH));
                }
        );
    }

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.define(DATA_PLAYER_UUID, Optional.empty());
        this.entityData.define(DATA_PLAYER_NAME, "");
        this.entityData.define(DATA_PLAYER_MODE_CUSTOMISATION, (byte) 0);
        this.entityData.define(DATA_PLAYER_HEALTH, new CompoundTag());
    }

    @Override
    public Iterable<ItemStack> getArmorSlots() {
        return java.util.Collections.emptyList();
    }

    @Override
    public ItemStack getItemBySlot(net.minecraft.world.entity.EquipmentSlot slot) {
        return ItemStack.EMPTY;
    }

    @Override
    public void setItemSlot(net.minecraft.world.entity.EquipmentSlot slot, ItemStack stack) {

    }

    @Override
    public HumanoidArm getMainArm() {
        return HumanoidArm.RIGHT;
    }

    public void setPlayerUUID(UUID uuid) {
        this.entityData.set(DATA_PLAYER_UUID, Optional.ofNullable(uuid));
    }

    public Optional<UUID> getPlayerUUID() {
        return this.entityData.get(DATA_PLAYER_UUID);
    }

    public void setPlayerName(String name) {
        this.entityData.set(DATA_PLAYER_NAME, name);
    }

    public String getPlayerName() {
        return this.entityData.get(DATA_PLAYER_NAME);
    }

    public byte getModelCustomisation() {
        return this.entityData.get(DATA_PLAYER_MODE_CUSTOMISATION);
    }

    public void setModelCustomisation(byte customisation) {
        this.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, customisation);
    }

    public void setPlayerHealthData(PlayerHealthData ph) {
        CompoundTag nbt = new CompoundTag();
        nbt = ph.serializeNBT(nbt);

        this.entityData.set(DATA_PLAYER_HEALTH, nbt);
    }

    public PlayerHealthData getPlayerHealthData() {
        PlayerHealthData ph = new PlayerHealthData();

        ph.deserializeNBT(this.entityData.get(DATA_PLAYER_HEALTH));

        return ph;
    }

    @Override
    public void addAdditionalSaveData(CompoundTag compound) {
        super.addAdditionalSaveData(compound);
        getPlayerUUID().ifPresent(uuid -> compound.putUUID("PlayerUUID", uuid));
        compound.putString("PlayerName", getPlayerName());

        CompoundTag nbt = getPlayerHealthData().serializeNBT(new CompoundTag());
        compound.put("PlayerHealth", nbt);
    }

    @Override
    public void readAdditionalSaveData(CompoundTag compound) {
        super.readAdditionalSaveData(compound);
        if (compound.hasUUID("PlayerUUID")) {
            setPlayerUUID(compound.getUUID("PlayerUUID"));
        }
        if (compound.contains("PlayerName")) {
            setPlayerName(compound.getString("PlayerName"));
        }
        if (compound.contains("PlayerHealth")) {
            PlayerHealthData ph = new PlayerHealthData();
            ph.deserializeNBT(compound.getCompound("PlayerHealth"));
            setPlayerHealthData(ph);
        }
    }

    @Override
    public void tick() {
        super.tick();
    }
}