/*
 * Copyright (c) 2026 盐灯水母
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package com.remains_cave.entity.client;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import com.remains_cave.client.model.ArrowModelLoader;
import com.remains_cave.item.custom.TombBowItem;
import com.remains_cave.item.custom.TombQuiverItem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.alchemy.PotionContents;
import software.bernie.geckolib.animatable.GeoItem;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.cache.object.GeoBone;
import software.bernie.geckolib.cache.object.GeoCube;
import software.bernie.geckolib.renderer.GeoItemRenderer;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;

public class TombBowRenderer extends GeoItemRenderer<TombBowItem> {
    private Player currentPlayer;
    private ItemStack currentArrowStack;

    public TombBowRenderer() {
        super(new TombBowModel());
    }
    private ItemStack getArrowFromQuiver(Player player) {
        // 假设箭袋固定在副手（根据您的设计）
        ItemStack offhand = player.getOffhandItem();
        if (offhand.getItem() instanceof TombQuiverItem) {
            return TombQuiverItem.getFirstArrow(offhand);
        }
        // 可选：检查主手或其他槽位（如需要）
        return ItemStack.EMPTY;
    }

    @Override
    public void renderByItem(ItemStack stack, ItemDisplayContext transformType,
                             PoseStack poseStack, MultiBufferSource bufferSource,
                             int light, int overlay) {
        currentPlayer = Minecraft.getInstance().player;
        boolean isThisStackBeingUsed = false;
        currentArrowStack = ItemStack.EMPTY;

        if (currentPlayer != null && currentPlayer.isUsingItem()) {
            ItemStack useItem = currentPlayer.getUseItem();
            if (!useItem.isEmpty()) {
                long useId = GeoItem.getId(useItem);
                long thisId = GeoItem.getId(stack);
                if (thisId != Long.MAX_VALUE && useId == thisId) {
                    isThisStackBeingUsed = true;

                    // 优先从箭袋获取箭矢
                    ItemStack arrowFromQuiver = getArrowFromQuiver(currentPlayer);
                    if (!arrowFromQuiver.isEmpty()) {
                        currentArrowStack = arrowFromQuiver;
                    } else {
                        currentArrowStack = currentPlayer.getProjectile(useItem);
                    }
                }
            }
        }

        boolean isPulling = isThisStackBeingUsed;

        poseStack.pushPose();

        if (transformType == ItemDisplayContext.GUI) {
            poseStack.mulPose(Axis.YP.rotationDegrees(90));
            poseStack.mulPose(Axis.XP.rotationDegrees(45));
            poseStack.translate(0, 0.325, -0.8);
        } else if (transformType == ItemDisplayContext.FIRST_PERSON_RIGHT_HAND) {
            if (isPulling) {
                poseStack.mulPose(Axis.XP.rotationDegrees(19));
                poseStack.mulPose(Axis.YP.rotationDegrees(-10));
                poseStack.translate(0.17, 0.45, -0.765);
            } else {
                poseStack.mulPose(Axis.XP.rotationDegrees(5));
                poseStack.mulPose(Axis.YP.rotationDegrees(5));
                poseStack.mulPose(Axis.ZP.rotationDegrees(-5));
                poseStack.translate(-0.15, 0.4, -0.165);
            }
        } else if (transformType == ItemDisplayContext.FIRST_PERSON_LEFT_HAND) {
            if (isPulling) {
                poseStack.mulPose(Axis.XP.rotationDegrees(19));
                poseStack.mulPose(Axis.YP.rotationDegrees(10));
                poseStack.translate(-0.245, 0.45, -0.665);
            } else {
                poseStack.mulPose(Axis.XP.rotationDegrees(5));
                poseStack.mulPose(Axis.YP.rotationDegrees(-5));
                poseStack.mulPose(Axis.ZP.rotationDegrees(5));
                poseStack.translate(0.125, 0.3, -0.265);
            }
        } else if (transformType == ItemDisplayContext.GROUND) {
            poseStack.mulPose(Axis.ZP.rotationDegrees(-5));
            poseStack.mulPose(Axis.YP.rotationDegrees(5));
            poseStack.mulPose(Axis.XP.rotationDegrees(5));
            poseStack.translate(-0.15, 0.3, -0.165);
            poseStack.mulPose(Axis.XP.rotationDegrees(45));
            poseStack.translate(0, 0.5, -0.5);
        } else if (transformType == ItemDisplayContext.FIXED) {
            poseStack.mulPose(Axis.YP.rotationDegrees(90));
            poseStack.mulPose(Axis.ZP.rotationDegrees(180));
            poseStack.mulPose(Axis.XP.rotationDegrees(-135));
            poseStack.translate(0, -0.4, -1.5);
        }

        super.renderByItem(stack, transformType, poseStack, bufferSource, light, overlay);
        poseStack.popPose();

        currentPlayer = null;
        currentArrowStack = ItemStack.EMPTY;
    }

    @Override
    public void renderRecursively(PoseStack poseStack, TombBowItem animatable, GeoBone bone,
                                  RenderType renderType, MultiBufferSource bufferSource,
                                  VertexConsumer buffer, boolean isReRender, float partialTick,
                                  int packedLight, int packedOverlay, int packedColor) {
        if (bone.getName().equals("arrow_anchor") && currentPlayer != null && !currentArrowStack.isEmpty()) {
            poseStack.pushPose();
            applyBoneTransform(poseStack, bone);

            BakedGeoModel arrowModel = ArrowModelLoader.getArrowModel(currentArrowStack.getItem());

            if (arrowModel != null) {
                ResourceLocation arrowTexture;
                if (arrowModel == ArrowModelLoader.getDefaultArrowModel()) {
                    arrowTexture = ResourceLocation.parse("remains_cave:textures/item/arrow/arrow_default.png");
                } else {
                    arrowTexture = getArrowTexture(currentArrowStack);
                }

                int defaultColor = 0xFFFFFFFF;
                int potionColor = defaultColor;
                PotionContents potionContents = currentArrowStack.get(DataComponents.POTION_CONTENTS);
                if (potionContents != null) {
                    potionColor = potionContents.getColor();
                }

                RenderType arrowRenderType = RenderType.entityCutoutNoCull(arrowTexture);
                VertexConsumer arrowBuffer = bufferSource.getBuffer(arrowRenderType);

                Collection<GeoBone> rootBones = getRootBones(arrowModel);
                for (GeoBone rootBone : rootBones) {
                    renderBoneTree(poseStack, rootBone, arrowRenderType, arrowTexture, bufferSource, arrowBuffer,
                            isReRender, partialTick, packedLight, packedOverlay, defaultColor, potionColor);
                }
            }

            poseStack.popPose();
            return;
        }
        super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer,
                isReRender, partialTick, packedLight, packedOverlay, packedColor);
    }

    @SuppressWarnings("unchecked")
    private Collection<GeoBone> getRootBones(BakedGeoModel model) {
        try {
            Field field = model.getClass().getDeclaredField("topLevelBones");
            field.setAccessible(true);
            Object value = field.get(model);
            if (value instanceof Collection) {
                return (Collection<GeoBone>) value;
            }
        } catch (Exception ignored) {}
        return Collections.emptyList();
    }

    private void renderBoneTree(PoseStack poseStack, GeoBone bone, RenderType renderType, ResourceLocation texture,
                                MultiBufferSource bufferSource, VertexConsumer buffer,
                                boolean isReRender, float partialTick, int packedLight,
                                int packedOverlay, int defaultColor, int potionColor) {
        poseStack.pushPose();
        applyBoneTransform(poseStack, bone);

        if (!bone.isHidden()) {
            for (GeoCube cube : bone.getCubes()) {
                poseStack.pushPose();

                int colorToUse = bone.getName().equals("arrowhead") ? potionColor : defaultColor;

                // 对光灵箭的发光核心使用自发光渲染
                if (bone.getName().equals("glow_core")) {
                    RenderType glowRenderType = RenderType.entityTranslucentEmissive(texture);
                    VertexConsumer glowBuffer = bufferSource.getBuffer(glowRenderType);
                    renderCube(poseStack, cube, glowBuffer, 0xF000F0, packedOverlay, colorToUse);
                } else {
                    renderCube(poseStack, cube, buffer, packedLight, packedOverlay, colorToUse);
                }

                poseStack.popPose();
            }
        }

        for (GeoBone child : bone.getChildBones()) {
            renderBoneTree(poseStack, child, renderType, texture, bufferSource, buffer,
                    isReRender, partialTick, packedLight, packedOverlay, defaultColor, potionColor);
        }

        poseStack.popPose();
    }

    private void applyBoneTransform(PoseStack poseStack, GeoBone bone) {
        poseStack.translate(bone.getPosX() / 16f, bone.getPosY() / 16f, bone.getPosZ() / 16f);
        poseStack.translate(bone.getPivotX() / 16f, bone.getPivotY() / 16f, bone.getPivotZ() / 16f);
        if (bone.getRotZ() != 0) poseStack.mulPose(Axis.ZP.rotation(bone.getRotZ()));
        if (bone.getRotY() != 0) poseStack.mulPose(Axis.YP.rotation(bone.getRotY()));
        if (bone.getRotX() != 0) poseStack.mulPose(Axis.XP.rotation(bone.getRotX()));
        poseStack.scale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ());
    }

    private ResourceLocation getArrowTexture(ItemStack arrowStack) {
        if (arrowStack.isEmpty()) {
            return ResourceLocation.parse("remains_cave:textures/item/arrow/arrow_default.png");
        }
        ResourceLocation itemId = arrowStack.getItem().builtInRegistryHolder().key().location();
        return ResourceLocation.parse(itemId.getNamespace() + ":textures/item/arrow/" +
                itemId.getNamespace() + "_" + itemId.getPath().replace('/', '_') + ".png");
    }
}