import { ItemStack, Direction, BlockPermutation, world } from "@minecraft/server";
import { getPlayerHoldingItem } from "../../utils/inventory";

/**
 * Checks if the block is a double slab.
 * @param {import("@minecraft/server").Block} block - The block to check.
 * @param {string} namespace - The namespace of the block.
 * @returns {boolean} True if the block is a double slab, false otherwise.
 */
function isDoubleSlab(block) {
    return block.permutation.getState("gs_ce:is_double");
}

/**
 * Checks if the block matches the given item ID.
 * @param {import("@minecraft/server").Block} block - The block to check.
 * @param {string} itemId - The item ID to match.
 * @returns {boolean} True if the block matches the item ID, false otherwise.
 */
function isMatchingSlab(block, itemId) {
    return block.typeId === itemId;
}

/**
 * turns a direction into a vector3.
 * @param {import("@minecraft/server").Direction} direction - The direction to convert.
 * @returns {import("@minecraft/server").Vector3} The vector3 of the direction.
 */
export function directionToVector3(direction) {
    switch (direction) {
        case Direction.Down:
            return { x: 0, y: -1, z: 0 };
        case Direction.Up:
            return { x: 0, y: 1, z: 0 };
        case Direction.North:
            return { x: 0, y: 0, z: -1 };
        case Direction.South:
            return { x: 0, y: 0, z: 1 };
        case Direction.West:
            return { x: -1, y: 0, z: 0 };
        case Direction.East:
            return { x: 1, y: 0, z: 0 };
    }
}

/**
 * Returns the opposite direction of the given direction.
 *
 * @param {import("@minecraft/server").Direction} direction - The direction to get the opposite of.
 * @returns {import("@minecraft/server").Direction} The opposite direction.
 */
export function getOppositeDirection(direction) {
    switch (direction) {
        case Direction.Up:
            return Direction.Down;
        case Direction.Down:
            return Direction.Up;
        case Direction.North:
            return Direction.South;
        case Direction.East:
            return Direction.West;
        case Direction.South:
            return Direction.North;
        case Direction.West:
            return Direction.East;
        default:
            break;
    }
}

/**
 * Handles the vertical half of the block.
 * @param {import("@minecraft/server").Block} block - The block to handle.
 * @param {import("@minecraft/server").Direction} face - The direction of the face.
 * @param {string} blockStateHalf - The block state half.
 * @returns {boolean} True if the block is handled, false otherwise.
 */
function handleVerticalHalf(block, face, blockStateHalf) {
    const state = block.permutation.getState(blockStateHalf);
    return (face === "Down" && state === "top") || (face === "Up" && state === "bottom");
}

world.beforeEvents.worldInitialize.subscribe(({ blockComponentRegistry }) => {
    blockComponentRegistry.registerCustomComponent("gs_ce:custom_slab", {
        beforeOnPlayerPlace: (data) => {
            const { block, player, face, dimension } = data;
            const equippableComponent = player.getComponent("minecraft:equippable");
            const itemStack = equippableComponent.getEquipment("Mainhand");

            if (!itemStack) return;

            const oppositeFace = getOppositeDirection(face);
            const blockToCheck = block.offset(directionToVector3(oppositeFace));
            const blockStateDouble = "gs_ce:is_double";
            const blockStateHalf = "minecraft:vertical_half";

            if (isDoubleSlab(blockToCheck) || !isMatchingSlab(blockToCheck, itemStack.typeId)) return;

            if (face === "Up" || face === "Down") {
                if (handleVerticalHalf(blockToCheck, face, blockStateHalf)) {
                    data.cancel = true;
                    blockToCheck.setPermutation(
                        BlockPermutation.resolve(blockToCheck.typeId, {
                            [blockStateDouble]: true,
                        })
                    );
                    dimension.playSound("use.wood", block.location);
                    if (player.getGameMode() === "creative") return;
                    if (itemStack.amount > 1) {
                        itemStack.amount--;
                        equippableComponent.setEquipment("Mainhand", itemStack);
                    } else {
                        equippableComponent.setEquipment("Mainhand", undefined);
                    }
                }
            }
        }
    });
});
