package com.straice.smoothdoors.client.anim;

import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.block.TrapdoorBlock;
import net.minecraft.block.enums.BlockHalf;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.BlockRenderView;

final class TrapdoorAnimation {

    private TrapdoorAnimation() {}

    static void apply(BlockState state, float baseAngleDeg, MatrixStack matrices, BlockRenderView world) {
        if (world == null) return;

        Direction facing = state.get(TrapdoorBlock.FACING);
        BlockHalf half = state.get(TrapdoorBlock.HALF);

        VoxelShape collShape = state.getCollisionShape(world, BlockPos.ORIGIN, ShapeContext.absent());
        Box bb = collShape.isEmpty()
                ? state.getOutlineShape(world, BlockPos.ORIGIN, ShapeContext.absent()).getBoundingBox()
                : collShape.getBoundingBox();

        Direction hingeSide = facing.getOpposite();

        float pivotX = (float) ((bb.minX + bb.maxX) * 0.5);
        float pivotZ = (float) ((bb.minZ + bb.maxZ) * 0.5);
        switch (hingeSide) {
            case NORTH -> pivotZ = (float) bb.minZ;
            case SOUTH -> pivotZ = (float) bb.maxZ;
            case WEST -> pivotX = (float) bb.minX;
            case EAST -> pivotX = (float) bb.maxX;
            default -> {
                pivotX = (float) ((bb.minX + bb.maxX) * 0.5);
                pivotZ = (float) ((bb.minZ + bb.maxZ) * 0.5);
            }
        }
        float pivotY = (half == BlockHalf.TOP) ? (float) bb.maxY : (float) bb.minY;

        float angle;
        switch (hingeSide) {
            case NORTH, EAST -> angle = -baseAngleDeg;
            case SOUTH, WEST -> angle = baseAngleDeg;
            default -> angle = baseAngleDeg;
        }
        if (half == BlockHalf.TOP) angle = -angle;

        float thickness = (float) (bb.maxY - bb.minY);
        float halfT = thickness > 0.0f ? thickness * 0.5f : (3.0f / 32.0f);
        float dY = (half == BlockHalf.TOP) ? -halfT : halfT;

        double rad = Math.toRadians(angle);
        float cos = (float) Math.cos(rad);
        float sin = (float) Math.sin(rad);

        float shiftX = 0.0f;
        float shiftY = 0.0f;
        float shiftZ = 0.0f;
        if (hingeSide == Direction.NORTH || hingeSide == Direction.SOUTH) {
            float rotY = dY * cos;
            float rotZ = dY * sin;
            shiftY = dY - rotY;
            shiftZ = -rotZ;
        } else {
            float rotX = -dY * sin;
            float rotY = dY * cos;
            shiftX = -rotX;
            shiftY = dY - rotY;
        }

        matrices.translate(shiftX, shiftY, shiftZ);
        matrices.translate(pivotX, pivotY, pivotZ);
        if (hingeSide == Direction.NORTH || hingeSide == Direction.SOUTH) {
            matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(angle));
        } else {
            matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(angle));
        }
        matrices.translate(-pivotX, -pivotY, -pivotZ);
        matrices.translate(-shiftX, -shiftY, -shiftZ);
    }
}
