package top.r3944realms.lib39.util;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerInfo;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.util.nbt.NBTReader;
import top.r3944realms.lib39.util.nbt.NBTWriter;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

/**
 * The type GameProfile helper.
 */
public class GameProfileHelper {
    /**
     * The constant TAG_BE.
     */
    public static final String TAG_BE = "BlockEntityTag";
    /**
     * The constant TAG_OWN_PROFILE.
     */
    public static final String TAG_OWN_PROFILE = "OwnerProfile";


    /**
     * Gets skin texture.
     *
     * @param gameProfile the game profile
     * @return the skin texture
     */
    @OnlyIn(Dist.CLIENT)
    public static ResourceLocation getSkinTexture(@Nullable GameProfile gameProfile) {
        if (gameProfile == null) {
            return DefaultPlayerSkin.getDefaultSkin();
        }
        return resolveSkinTexture(gameProfile);
    }

    /**
     * Resolve skin texture resource location.
     *
     * @param gameProfile the game profile
     * @return the resource location
     */
    @OnlyIn(Dist.CLIENT)
    public static @NotNull ResourceLocation resolveSkinTexture(@NotNull GameProfile gameProfile) {
        Minecraft minecraft = Minecraft.getInstance();
        return minecraft.getSkinManager()
                .getInsecureSkinLocation(gameProfile);
    }

    /**
     * Has slim arms boolean.
     *
     * @param player the player
     * @return the boolean
     */
// 判断玩家是否使用纤细手臂
    public static boolean hasSlimArms(@NotNull Player player) {
        if (player.level().isClientSide) {
            return hasSlimArmsClient(player);
        } else {
            return hasSlimArmsServer(player);
        }
    }

    // 客户端判断
    @OnlyIn(Dist.CLIENT)
    private static boolean hasSlimArmsClient(Player player) {
        if (player instanceof AbstractClientPlayer clientPlayer) {
            PlayerInfo playerInfo = Objects.requireNonNull(Minecraft.getInstance()
                            .getConnection())
                    .getPlayerInfo(clientPlayer.getUUID());
            return playerInfo != null && "slim".equals(playerInfo.getModelName());
        }
        return false;
    }

    // 服务器端判断
    private static boolean hasSlimArmsServer(@NotNull Player player) {
        GameProfile profile = player.getGameProfile();
        for (Property property : profile.getProperties().get("textures")) {
            try {
                String json = new String(Base64.getDecoder().decode(property.getValue()));
                JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
                JsonObject textures = obj.getAsJsonObject("textures");
                JsonObject skin = textures.getAsJsonObject("SKIN");

                if (skin.has("metadata")) {
                    JsonObject metadata = skin.getAsJsonObject("metadata");
                    if (metadata.has("model")) {
                        return "slim".equals(metadata.get("model").getAsString());
                    }
                }
            } catch (Exception e) {
                // 解析失败，使用默认
            }
        }
        return false;
    }

    /**
     * Gets skin model name.
     *
     * @param player the player
     * @return the skin model name
     */
// 获取皮肤模型名称
    @OnlyIn(Dist.CLIENT)
    public static @NotNull String getSkinModelName(@NotNull Player player) {
        if (player.level().isClientSide && player instanceof AbstractClientPlayer) {
            PlayerInfo info = Objects.requireNonNull(Minecraft.getInstance().getConnection())
                    .getPlayerInfo(player.getUUID());
            return info != null ? info.getModelName() : "default";
        }
        return "default";
    }

    /**
     * 判断玩家是否为纤细手臂（Alex模型）
     *
     * @param profile 玩家的GameProfile
     * @return true =纤细手臂，false=正常手臂
     */
    public static boolean isSlimArms(GameProfile profile) {
        if (profile == null) {
            return false;
        }

        // 获取textures属性
        Collection<Property> textures = profile.getProperties().get("textures");
        if (textures.isEmpty()) {
            return false; // 没有皮肤数据，使用默认
        }

        // 获取第一个texture属性（通常是皮肤）
        Property textureProperty = textures.iterator().next();
        String value = textureProperty.getValue();

        try {
            return isSlimFromTextureData(value);
        } catch (Exception e) {
            // 解析失败，使用默认
            return false;
        }
    }

    /**
     * 从Base64编码的皮肤数据判断
     * @param encodedTexture Base64编码的皮肤数据
     * @return true=纤细手臂
     */
    private static boolean isSlimFromTextureData(String encodedTexture) {
        if (encodedTexture == null || encodedTexture.isEmpty()) {
            return false;
        }

        try {
            // 1. Base64解码
            byte[] decodedBytes = Base64.getDecoder().decode(encodedTexture);
            String jsonString = new String(decodedBytes, StandardCharsets.UTF_8);

            // 2. 解析JSON
            JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();

            // 3. 导航到textures -> SKIN
            JsonObject textures = root.getAsJsonObject("textures");
            if (textures == null) {
                return false;
            }

            JsonObject skin = textures.getAsJsonObject("SKIN");
            if (skin == null) {
                return false;
            }

            // 4. 检查metadata -> model
            JsonObject metadata = skin.getAsJsonObject("metadata");
            if (metadata == null) {
                return false; // 没有metadata，使用默认
            }

            String model = metadata.get("model").getAsString();
            return "slim".equals(model);

        } catch (Exception e) {
            // 解析过程中出现任何错误，返回默认值
            return false;
        }
    }

    /**
     * 获取皮肤模型名称
     *
     * @param profile GameProfile
     * @return "slim" 或 "default"
     */
    public static String getSkinModelName(GameProfile profile) {
        if (profile == null) {
            return "default";
        }

        Collection<Property> textures = profile.getProperties().get("textures");
        if (textures.isEmpty()) {
            return "default";
        }

        Property textureProperty = textures.iterator().next();
        String value = textureProperty.getValue();

        try {
            byte[] decodedBytes = Base64.getDecoder().decode(value);
            String jsonString = new String(decodedBytes, StandardCharsets.UTF_8);
            JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
            JsonObject texturesObj = root.getAsJsonObject("textures");
            JsonObject skin = texturesObj.getAsJsonObject("SKIN");

            if (skin.has("metadata")) {
                JsonObject metadata = skin.getAsJsonObject("metadata");
                if (metadata.has("model")) {
                    return metadata.get("model").getAsString();
                }
            }
        } catch (Exception e) {
            // 忽略错误
        }

        return "default";
    }

    /**
     * 从ItemStack的NBT中读取GameProfile
     *
     * @param stack the stack
     * @return the profile from item stack
     */
    @Nullable
    public static GameProfile getProfileFromItemStack(ItemStack stack) {
        if (stack.isEmpty()) {
            return null;
        }

        CompoundTag tag = stack.getTag();
        if (tag == null) {
            return null;
        }
        AtomicReference<GameProfile> profileRef = new AtomicReference<>();
        // 检查方块实体数据
        NBTReader.of(tag)
                .compound(TAG_BE, compoundTag ->
                        NBTReader.of(compoundTag)
                            .compound("OwnerProfile", ct -> profileRef.set(NbtUtils.readGameProfile(ct)))
                )
                .compound("OwnerProfile", ct -> {
                    if (profileRef.get() == null) { //兼容写法
                        profileRef.set(NbtUtils.readGameProfile(ct));
                    }
                });
        return profileRef.get();
    }

    /**
     * 将GameProfile保存到ItemStack的NBT
     *
     * @param stack   the stack
     * @param profile the profile
     */
    public static void saveProfileToItemStack(@NotNull ItemStack stack, @Nullable GameProfile profile) {
        if (stack.isEmpty()) {
            return;
        }

        CompoundTag tag = stack.getOrCreateTag();

        if (profile == null) {
            // 移除现有数据
            NBTReader.of(tag)
                    .compound(TAG_BE, ct -> tag.remove(TAG_OWN_PROFILE));
            tag.remove(TAG_BE);
            tag.remove(TAG_OWN_PROFILE);
            return;
        }

        // 创建方块实体数据
        NBTWriter.of(tag)
                .compound(TAG_BE, writer ->
                        writer
                                .compound(TAG_OWN_PROFILE, NbtUtils.writeGameProfile(new CompoundTag(), profile))
                );
    }

    /**
     * 检查ItemStack是否有保存的皮肤数据
     *
     * @param stack the stack
     * @return the boolean
     */
    public static boolean hasProfileData(@NotNull ItemStack stack) {
        if (stack.isEmpty()) {
            return false;
        }

        CompoundTag tag = stack.getTag();
        if (tag == null) {
            return false;
        }

        if (tag.contains(TAG_BE)) {
            CompoundTag blockEntityTag = tag.getCompound(TAG_BE);
            return blockEntityTag.contains(TAG_OWN_PROFILE);
        }

        return tag.contains(TAG_OWN_PROFILE);
    }

}

