package com.tiedup.remake.client;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.PoseType;
import com.tiedup.remake.v2.bondage.PoseTypeHelper;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderArmEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

/**
 * Renders mittens on the player's arms in first-person view.
 *
 * Uses RenderArmEvent which fires specifically when a player's arm
 * is being rendered in first person. This is more targeted than RenderHandEvent.
 *
 * @see <a href="https://nekoyue.github.io/ForgeJavaDocs-NG/javadoc/1.18.2/net/minecraftforge/client/event/RenderArmEvent.html">RenderArmEvent Documentation</a>
 */
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
    modid = TiedUpMod.MOD_ID,
    bus = Mod.EventBusSubscriber.Bus.FORGE,
    value = Dist.CLIENT
)
public class FirstPersonMittensRenderer {

    private static final ResourceLocation MITTENS_TEXTURE =
        ResourceLocation.fromNamespaceAndPath(
            TiedUpMod.MOD_ID,
            "textures/models/bondage/mittens/mittens.png"
        );

    /**
     * Render mittens overlay on the player's arm in first-person view.
     *
     * This event fires after the arm is set up for rendering but we can add
     * our own rendering on top of it.
     */
    @SubscribeEvent
    public static void onRenderArm(RenderArmEvent event) {
        AbstractClientPlayer player = event.getPlayer();

        // Get player's bind state
        PlayerBindState state = PlayerBindState.getInstance(player);
        if (state == null) return;

        // If tied up, arms are hidden by FirstPersonHandHideHandler - don't render mittens
        if (state.isTiedUp()) return;

        // Check if player has mittens
        if (!state.hasMittens()) return;

        // Hide mittens when player is in a wrap or latex sack (hands are covered)
        if (isBindHidingMittens(player)) return;

        // Render mittens on this arm
        renderMittensOnArm(event);
    }

    /**
     * Render the mittens overlay on the arm.
     */
    private static void renderMittensOnArm(RenderArmEvent event) {
        PoseStack poseStack = event.getPoseStack();
        MultiBufferSource buffer = event.getMultiBufferSource();
        int packedLight = event.getPackedLight();
        AbstractClientPlayer player = event.getPlayer();
        HumanoidArm arm = event.getArm();

        // Get the player's model to access the arm ModelPart
        Minecraft mc = Minecraft.getInstance();
        var renderer = mc.getEntityRenderDispatcher().getRenderer(player);
        if (!(renderer instanceof PlayerRenderer playerRenderer)) return;

        PlayerModel<AbstractClientPlayer> playerModel =
            playerRenderer.getModel();

        poseStack.pushPose();

        // Get the appropriate arm from the player model
        ModelPart armPart = (arm == HumanoidArm.RIGHT)
            ? playerModel.rightArm
            : playerModel.leftArm;
        ModelPart sleevePart = (arm == HumanoidArm.RIGHT)
            ? playerModel.rightSleeve
            : playerModel.leftSleeve;

        // The arm is already positioned by the game's first-person renderer
        // We just need to render our mittens texture on top

        // Use a slightly scaled version to appear on top (avoid z-fighting)
        poseStack.scale(1.001F, 1.001F, 1.001F);

        // Render the arm with mittens texture
        VertexConsumer vertexConsumer = buffer.getBuffer(
            RenderType.entitySolid(MITTENS_TEXTURE)
        );

        // Render the arm part with mittens texture
        armPart.render(
            poseStack,
            vertexConsumer,
            packedLight,
            OverlayTexture.NO_OVERLAY
        );

        // Also render the sleeve part if visible
        if (sleevePart.visible) {
            sleevePart.render(
                poseStack,
                vertexConsumer,
                packedLight,
                OverlayTexture.NO_OVERLAY
            );
        }

        poseStack.popPose();
    }

    /**
     * Check if the player's current bind variant hides mittens.
     * WRAP and LATEX_SACK cover the entire body including hands.
     */
    private static boolean isBindHidingMittens(AbstractClientPlayer player) {
        net.minecraft.world.item.ItemStack bindStack =
            V2EquipmentHelper.getInRegion(player, BodyRegionV2.ARMS);
        if (bindStack.isEmpty()) return false;
        PoseType poseType = PoseTypeHelper.getPoseType(bindStack);
        return poseType == PoseType.WRAP || poseType == PoseType.LATEX_SACK;
    }
}
