package top.r3944realms.lib39.client.model;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.Model;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.builders.*;
import net.minecraft.client.renderer.RenderType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.Lib39;

/**
 * The type Doll model.
 */
public class DollModel extends Model {
    /**
     * The constant LAYER_LOCATION.
     */
    public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(Lib39.rl("doll_model"), "main");
    /**
     * The Slim.
     */
    public boolean slim = false;
    private final ModelPart head;
    private final ModelPart body;
    private final ModelPart rightArm;
    private final ModelPart leftArm;
    private final ModelPart rightLeg;
    private final ModelPart rightArmSlim;
    private final ModelPart leftArmSlim;
    private final ModelPart leftLeg;
    @Nullable
    private IDollPose currentPose;

    /**
     * Gets current pose.
     *
     * @return the current pose
     */
    @Nullable
    public IDollPose getCurrentPose() {
        return currentPose;
    }

    /**
     * Sets doll pose.
     *
     * @param dollPose the doll pose
     */
    public void setDollPose(@NotNull IDollPose dollPose) {
        this.currentPose = dollPose;
        this.head.loadPose(dollPose.getHeadPose());
        this.body.loadPose(dollPose.getBodyPose());
        this.rightArm.loadPose(dollPose.getRightArmPose());
        this.leftArm.loadPose(dollPose.getLeftArmPose());
        this.rightArmSlim.loadPose(dollPose.getRightArmPose());
        this.leftArmSlim.loadPose(dollPose.getLeftArmPose());
        this.rightLeg.loadPose(dollPose.getRightLegPose());
        this.leftLeg.loadPose(dollPose.getLeftLegPose());
    }

    /**
     * Reset pose.
     */
    public void resetPose() {
        this.currentPose = DollPoses.DEFAULT;
        this.head.resetPose();
        this.body.resetPose();
        this.rightArm.resetPose();
        this.leftArm.resetPose();
        this.rightArmSlim.resetPose();
        this.leftArmSlim.resetPose();
        this.rightLeg.resetPose();
        this.leftLeg.resetPose();
    }

    /**
     * Instantiates a new Doll model.
     *
     * @param root the root
     */
    public DollModel(@NotNull ModelPart root) {
        super(RenderType::entityTranslucent);
        this.head = root.getChild("head");
        this.body = root.getChild("body");
        this.rightArm = root.getChild("right_arm");
        this.leftArm = root.getChild("left_arm");
        this.rightArmSlim = root.getChild("right_arm_slim");
        this.leftArmSlim = root.getChild("left_arm_slim");
        this.rightLeg = root.getChild("right_leg");
        this.leftLeg = root.getChild("left_leg");
    }

    /**
     * Create body layer layer definition.
     *
     * @return the layer definition
     */
    public static @NotNull LayerDefinition createBodyLayer() {
        return createBodyLayer(DollPoses.DEFAULT);
    }

    private static @NotNull LayerDefinition createBodyLayer(@NotNull IDollPose dollPoses) {
        MeshDefinition meshdefinition = new MeshDefinition();
        PartDefinition partdefinition = meshdefinition.getRoot();
        partdefinition.addOrReplaceChild(
                "head",
                CubeListBuilder.create()
                        .texOffs(0, 0)
                        .addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.0F))
                        .texOffs(32, 0)
                        .addBox(
                                -4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F,
                                new CubeDeformation(0.5F)
                        ), dollPoses.getHeadPose()
        );
        partdefinition.addOrReplaceChild(
                "body",
                CubeListBuilder.create()
                        .texOffs(16, 16)
                        .addBox(-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
                        .texOffs(16, 32)
                        .addBox(
                                -4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F,
                                new CubeDeformation(0.25F)
                        ), dollPoses.getBodyPose()
        );
        partdefinition.addOrReplaceChild(
                "right_arm",
                CubeListBuilder.create()
                        .texOffs(40, 16)
                        .addBox(-3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
                        .texOffs(40, 32)
                        .addBox(
                                -3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F,
                                new CubeDeformation(0.25F)
                        ), dollPoses.getRightArmPose()
        );
        partdefinition.addOrReplaceChild(
                "right_arm_slim",
                CubeListBuilder.create()
                        .texOffs(40, 16)
                        .addBox(-2.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
                        .texOffs(40, 32)
                        .addBox(-2.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F,
                                new CubeDeformation(0.25F)
                        ), dollPoses.getRightArmPose()
        );
        partdefinition.addOrReplaceChild(
                "left_arm_slim",
                CubeListBuilder.create()
                        .texOffs(32, 48)
                        .addBox(-1.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
                        .texOffs(48, 48)
                        .addBox(
                                -1.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F,
                                new CubeDeformation(0.25F)
                        ), dollPoses.getLeftArmPose()
                );
        partdefinition.addOrReplaceChild(
                "left_arm",
                CubeListBuilder.create()
                        .texOffs(32, 48)
                        .addBox(-1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
                        .texOffs(48, 48)
                        .addBox(
                                -1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F,
                                new CubeDeformation(0.25F)
                        ), dollPoses.getLeftArmPose()
        );
        partdefinition.addOrReplaceChild(
                "right_leg",
                CubeListBuilder.create()
                        .texOffs(0, 16)
                        .addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
                        .texOffs(0, 32)
                        .addBox(
                                -2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)
                        ), dollPoses.getRightLegPose()
        );
        partdefinition.addOrReplaceChild(
                "left_leg",
                CubeListBuilder.create()
                        .texOffs(16, 48)
                        .addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
                        .texOffs(0, 48)
                        .addBox(
                                -2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F,
                                new CubeDeformation(0.25F)
                        ), dollPoses.getLeftLegPose()
        );
        return LayerDefinition.create(meshdefinition, 64, 64);
    }

    @Override
    public void renderToBuffer(@NotNull PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, int color) {
        poseStack.pushPose();
        poseStack.scale(0.5F, 0.5F, 0.5F);
        poseStack.translate(0.0, 1.5010000467300415, 0.0);
        this.head.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
        this.body.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
        if (this.slim) {
            this.rightArmSlim.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
            this.leftArmSlim.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
        } else {
            this.rightArm.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
            this.leftArm.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
        }
        this.rightLeg.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
        this.leftLeg.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
        poseStack.popPose();
    }
}
