package com.trunksbomb.minetriad.client.render;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;

import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;

public final class FirstPersonCardHandRenderer {
    private FirstPersonCardHandRenderer() {
    }

    public static void render(
            InteractionHand hand,
            PoseStack poseStack,
            MultiBufferSource buffer,
            int packedLight,
            float pitch,
            float swingProgress,
            float equipProgress,
            ItemStack stack) {
        Minecraft minecraft = Minecraft.getInstance();
        AbstractClientPlayer player = minecraft.player;
        if (player == null) {
            return;
        }

        HumanoidArm arm = hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite();
        boolean useTwoHanded = hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty();

        poseStack.pushPose();
        if (useTwoHanded) {
            renderTwoHandedCard(minecraft, player, poseStack, buffer, packedLight, pitch, equipProgress, swingProgress, stack);
        } else {
            renderOneHandedCard(minecraft, player, poseStack, buffer, packedLight, equipProgress, arm, swingProgress, stack);
        }
        poseStack.popPose();
    }

    private static void renderTwoHandedCard(
            Minecraft minecraft,
            AbstractClientPlayer player,
            PoseStack poseStack,
            MultiBufferSource buffer,
            int packedLight,
            float pitch,
            float equipProgress,
            float swingProgress,
            ItemStack stack) {
        float rootSwing = Mth.sqrt(swingProgress);
        float swingY = -0.2F * Mth.sin(swingProgress * (float) Math.PI);
        float swingZ = -0.4F * Mth.sin(rootSwing * (float) Math.PI);
        poseStack.translate(0.0F, -swingY / 2.0F, swingZ);

        float tilt = calculateCardTilt(pitch);
        poseStack.translate(0.0F, 0.04F + equipProgress * -1.2F + tilt * -0.5F, -0.72F);
        poseStack.mulPose(Axis.XP.rotationDegrees(tilt * -85.0F));

        if (!player.isInvisible()) {
            poseStack.pushPose();
            poseStack.mulPose(Axis.YP.rotationDegrees(90.0F));
            renderCardHand(minecraft, player, poseStack, buffer, packedLight, HumanoidArm.RIGHT);
            renderCardHand(minecraft, player, poseStack, buffer, packedLight, HumanoidArm.LEFT);
            poseStack.popPose();
        }

        float swingTilt = Mth.sin(rootSwing * (float) Math.PI);
        poseStack.mulPose(Axis.XP.rotationDegrees(swingTilt * 20.0F));
        poseStack.scale(2.0F, 2.0F, 2.0F);
        renderCenteredCard(poseStack, buffer, stack);
    }

    private static void renderOneHandedCard(
            Minecraft minecraft,
            AbstractClientPlayer player,
            PoseStack poseStack,
            MultiBufferSource buffer,
            int packedLight,
            float equipProgress,
            HumanoidArm arm,
            float swingProgress,
            ItemStack stack) {
        float armSign = arm == HumanoidArm.RIGHT ? 1.0F : -1.0F;
        poseStack.translate(armSign * 0.51F, -0.08F + equipProgress * -1.2F, -0.75F);

        float rootSwing = Mth.sqrt(swingProgress);
        float swingSin = Mth.sin(rootSwing * (float) Math.PI);
        float swingX = -0.5F * swingSin;
        float swingY = 0.4F * Mth.sin(rootSwing * (float) (Math.PI * 2));
        float swingZ = -0.3F * Mth.sin(swingProgress * (float) Math.PI);
        poseStack.translate(armSign * swingX, swingY - 0.3F * swingSin, swingZ);
        poseStack.mulPose(Axis.XP.rotationDegrees(swingSin * -45.0F));
        poseStack.mulPose(Axis.YP.rotationDegrees(armSign * swingSin * -30.0F));

        if (!player.isInvisible()) {
            poseStack.pushPose();
            poseStack.mulPose(Axis.ZP.rotationDegrees(armSign * 10.0F));
            renderPlayerArm(minecraft, player, poseStack, buffer, packedLight, equipProgress, swingProgress, arm);
            poseStack.popPose();
        }

        renderCenteredCard(poseStack, buffer, stack);
    }

    private static void renderCenteredCard(PoseStack poseStack, MultiBufferSource buffer, ItemStack stack) {
        poseStack.translate(0.0F, 0.0F, -0.18F);
        poseStack.scale(0.513F, 0.513F, 0.513F);
        TriadCardItemRenderer.renderCard(stack, poseStack, buffer, TriadCardItemRenderer.neutralPalette());
    }

    private static void renderCardHand(
            Minecraft minecraft,
            AbstractClientPlayer player,
            PoseStack poseStack,
            MultiBufferSource buffer,
            int packedLight,
            HumanoidArm arm) {
        PlayerRenderer renderer = getPlayerRenderer(minecraft, player);
        poseStack.pushPose();
        float armSign = arm == HumanoidArm.RIGHT ? 1.0F : -1.0F;
        poseStack.mulPose(Axis.YP.rotationDegrees(92.0F));
        poseStack.mulPose(Axis.XP.rotationDegrees(45.0F));
        poseStack.mulPose(Axis.ZP.rotationDegrees(armSign * -41.0F));
        poseStack.translate(armSign * 0.3F, -1.1F, 0.45F);
        if (arm == HumanoidArm.RIGHT) {
            renderer.renderRightHand(poseStack, buffer, packedLight, player);
        } else {
            renderer.renderLeftHand(poseStack, buffer, packedLight, player);
        }
        poseStack.popPose();
    }

    private static void renderPlayerArm(
            Minecraft minecraft,
            AbstractClientPlayer player,
            PoseStack poseStack,
            MultiBufferSource buffer,
            int packedLight,
            float equipProgress,
            float swingProgress,
            HumanoidArm arm) {
        PlayerRenderer renderer = getPlayerRenderer(minecraft, player);
        float armSign = arm == HumanoidArm.RIGHT ? 1.0F : -1.0F;
        float swingRoot = Mth.sqrt(swingProgress);
        float swingY = -0.3F * Mth.sin(swingRoot * (float) Math.PI);
        float swingZ = 0.4F * Mth.sin(swingRoot * (float) (Math.PI * 2));
        float swingX = -0.4F * Mth.sin(swingProgress * (float) Math.PI);
        poseStack.translate(armSign * (swingX + 0.64F), swingY + -0.6F + equipProgress * -0.6F, swingZ + -0.72F);
        poseStack.mulPose(Axis.YP.rotationDegrees(armSign * 45.0F));
        float armSwing = Mth.sin(swingProgress * swingProgress * (float) Math.PI);
        float armSwingRoot = Mth.sin(swingRoot * (float) Math.PI);
        poseStack.mulPose(Axis.YP.rotationDegrees(armSign * armSwingRoot * 70.0F));
        poseStack.mulPose(Axis.ZP.rotationDegrees(armSign * armSwing * -20.0F));
        poseStack.translate(armSign * -1.0F, 3.6F, 3.5F);
        poseStack.mulPose(Axis.ZP.rotationDegrees(armSign * 120.0F));
        poseStack.mulPose(Axis.XP.rotationDegrees(200.0F));
        poseStack.mulPose(Axis.YP.rotationDegrees(armSign * -135.0F));
        poseStack.translate(armSign * 5.6F, 0.0F, 0.0F);
        if (arm == HumanoidArm.RIGHT) {
            renderer.renderRightHand(poseStack, buffer, packedLight, player);
        } else {
            renderer.renderLeftHand(poseStack, buffer, packedLight, player);
        }
    }

    private static PlayerRenderer getPlayerRenderer(Minecraft minecraft, AbstractClientPlayer player) {
        EntityRenderDispatcher dispatcher = minecraft.getEntityRenderDispatcher();
        return (PlayerRenderer) dispatcher.getRenderer(player);
    }

    private static float calculateCardTilt(float pitch) {
        float tilt = 1.0F - pitch / 67.5F + 0.1F;
        tilt = Mth.clamp(tilt, 0.0F, 1.0F);
        return -Mth.cos(tilt * (float) Math.PI) * 0.5F + 0.5F;
    }
}
