import * as mc from "@minecraft/server";

export function capitalize(str) {
    return str
        .replace(/_/g, ' ')
        .replace(/\b\w/g, char => char.toUpperCase());
}

export function percentage(percentage, totalValue) {
    return (percentage / 100) * totalValue;
}

export function parseOrStringify(value, separator = ',') {
    if (typeof value === 'string') {
        return value.split(separator).map(item => item.trim());
    } else if (Array.isArray(value)) {
        return value.join(separator);
    }
}

export function stepsLimit(block, steps) {
    const loc = block.location;
    const maxY = 319;
    const minY = -64;
    const availableAbove = Math.min(steps, maxY - loc.y);
    const availableBelow = Math.min(steps, loc.y - minY);
    return {
        above: availableAbove,
        below: availableBelow
    };
}

export function getCardinalDirection(vector) {
    if (Math.abs(vector.y) > Math.abs(vector.x) && Math.abs(vector.y) > Math.abs(vector.z)) {
        return vector.y > 0 ? "above" : "below";
    }
    const angle = Math.atan2(vector.z, vector.x) * (180 / Math.PI);
    if (angle >= -45 && angle < 45) return "east";
    if (angle >= 45 && angle < 135) return "north";
    if (angle >= 135 || angle < -135) return "west";
    if (angle >= -135 && angle < -45) return "south";
}

export function updateItem(player, item) {
    const inv = player.getComponent('inventory').container
    inv.setItem(player.selectedSlotIndex, item)
}

export function ruleOfThree(maxNumber, symbolicNumber, number) {
    if (symbolicNumber === 0) return 0;
    const result = (number * maxNumber) / symbolicNumber;
    return result;
}

export function getRandomItem(array) {
    if (!Array.isArray(array) || array.length === 0) {
        throw new Error("O argumento deve ser uma array não vazia.");
    }
    const randomIndex = Math.floor(Math.random() * array.length);
    return array[randomIndex];
}

export function deleteItemEntity(entityItem, amount) {
    const itemStack = entityItem?.getComponent('minecraft:item')?.itemStack
    const loc = entityItem.location
    loc.y += 0.1
    if (itemStack) {
        if (itemStack.amount > amount) {
            itemStack.amount -= amount
            entityItem.dimension.spawnItem(itemStack, loc).teleport(loc)
            entityItem.remove()
        }
        if (itemStack.amount == amount) {
            try { entityItem.remove() } catch (e) { }
        }
    }
}

export function clearItem(block, slot, count) {
    let selectedSlot = block.getItem(slot);
    if (selectedSlot.amount > count) {
        selectedSlot.amount = selectedSlot.amount - count;
        block.setItem(slot, selectedSlot);
    } else {
        block.setItem(slot,);
    }
}

export function toRoman(num) {
    if (num <= 0 || num > 3999) return "Número fora do intervalo";

    const romanNumerals = [
        { value: 1000, numeral: "M" },
        { value: 900, numeral: "CM" },
        { value: 500, numeral: "D" },
        { value: 400, numeral: "CD" },
        { value: 100, numeral: "C" },
        { value: 90, numeral: "XC" },
        { value: 50, numeral: "L" },
        { value: 40, numeral: "XL" },
        { value: 10, numeral: "X" },
        { value: 9, numeral: "IX" },
        { value: 5, numeral: "V" },
        { value: 4, numeral: "IV" },
        { value: 1, numeral: "I" }
    ];

    let result = "";

    for (const { value, numeral } of romanNumerals) {
        while (num >= value) {
            result += numeral;
            num -= value;
        }
    }

    return result;
}

export function calculateDistance(vectorA, vectorB) {
    if (!vectorA || !vectorB) return undefined;
    const dx = vectorA.x - vectorB.x;
    const dy = vectorA.y - vectorB.y;
    const dz = vectorA.z - vectorB.z;
    return Math.sqrt(dx * dx + dy * dy + dz * dz);
}

export function compareVector3Int(a, b) {
    return (
      Math.floor(a.x) === Math.floor(b.x) &&
      Math.floor(a.y + 0.1) === Math.floor(b.y) &&
      Math.floor(a.z) === Math.floor(b.z)
    );
  }  

export function calculateDistanceWithoutY(vectorA, vectorB) {
    const dx = vectorA.x - vectorB.x;
    const dz = vectorA.z - vectorB.z;
    return Math.sqrt(dx * dx + dz * dz);
}

export function calculateMovement(start, end) {
    return {
        x: end.x - start.x,
        y: end.y - start.y,
        z: end.z - start.z
    }
}
export function clearMainhand(player, count) {
    if (player.getGameMode() == 'survival') {
        let selectedSlot = player.getComponent("equippable").getEquipment("Mainhand")
        if (selectedSlot.amount > count) {
            selectedSlot.amount = selectedSlot.amount - count;
            player.getComponent("equippable").setEquipment("Mainhand", selectedSlot);
        } else {
            let air = new mc.ItemStack("minecraft:air");
            player.getComponent("equippable").setEquipment("Mainhand", air);
        }
    } else {
        const selectedSlot = player.getComponent("equippable").getEquipment("Mainhand")
        selectedSlot.clearDynamicProperties()
        player.getComponent("equippable").setEquipment("Mainhand", selectedSlot);
    }
}
function clearOffhand(player, count) {
    let selectedSlot = player.getComponent("equippable").getEquipment("Offhand")
    if (selectedSlot.amount > count) {
        selectedSlot.amount = selectedSlot.amount - count;
        player.getComponent("equippable").setEquipment("Offhand", selectedSlot);
    } else {
        let air = new mc.ItemStack("minecraft:air");
        player.getComponent("equippable").setEquipment("Offhand", air);
    }
}
export function setPermutation(block, stateAdd, stateValue) {
    const result = block.permutation.getAllStates();
    result[stateAdd] = stateValue;
    block.setPermutation(mc.BlockPermutation.resolve(block?.typeId, result));
}
export function isBlockId(block, id) {
    try {
        let cm = block?.dimension?.runCommand(`setblock ${block?.location.x} -64 ${block?.location.z} ${id}`).successCount
        block?.dimension?.runCommand(`setblock ${block?.location.x} -64 ${block?.location.z} bedrock`)
        if (cm > 0) return true; else return false
    } catch (e) { }
}

export function applyDurability(item, amount, player) {
    if (item && amount) {
        const durability = item.getComponent('minecraft:durability')
        const currentValue = durability.maxDurability - durability.damage
        if (durability.damage + amount >= durability.maxDurability) {
            if (player) player.playSound('random.break');
            return new mc.ItemStack('minecraft:air')
        } else if (durability.damage + amount < durability.maxDurability) {
            item.getComponent('minecraft:durability').damage = item.getComponent('minecraft:durability').damage + amount
            return item
        }
    }
}

export function isJSONParsable(str) {
    try {
        JSON.parse(str);
        return true;
    } catch (e) {
        return false;
    }
}

export function removeStringFromArray(arr, str) {
    return arr.filter(item => item !== str);
}

export function generateCircleVectors(n, r, center) {
    let vectors = [];
    let angleIncrement = (2 * Math.PI) / n;

    for (let i = 0; i < n; i++) {
        let angle = i * angleIncrement;
        let x = center.x + r * Math.cos(angle);
        let y = center.y; // Presumindo que o círculo está no plano XZ
        let z = center.z + r * Math.sin(angle);
        vectors.push({ x: x, y: y, z: z });
    }

    return vectors;
}
export function calculateRelativeVector(vector1, vector2) {
    return {
        x: vector2.x - vector1.x,
        y: vector2.y - vector1.y,
        z: vector2.z - vector1.z
    };
}



export function blockFaceToDirection(face) {
    if (face == 'Up') return 'above'; else
        if (face == 'Down') return 'below'; else
            if (face?.includes('up')) return 'above'; else
                if (face?.includes('down')) return 'below'; else
                    if (face == 'North') return 'north'; else
                        if (face == 'South') return 'south'; else
                            if (face == 'West') return 'west'; else
                                if (face == 'East') return 'east'; else return (face)
}
export function invertFace(face) {
    if (face == 'above') return 'below'
    if (face == 'below') return 'above'
    if (face == 'north') return 'south'
    if (face == 'south') return 'north'
    if (face == 'west') return 'east'
    if (face == 'east') return 'west'

}
export function includesAnyIndex(str, arr) {
    return arr.findIndex(subStr => str.includes(subStr));
}
export function generateRandomID(length) {
    let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let randomID = '';
    for (let i = 0; i < length; i++) {
        randomID += characters.charAt(Math.floor(Math.random() * characters.length));
    }
    return randomID;
}

export const transformKey = str =>
    str.split(':')[1].replace(/_/g, ' ').toLowerCase().replace(/\b\w/g, c => c.toUpperCase())

const normalize = str => str.toLowerCase().replace(/[_ :]/g, '')
const filterProperties = (obj, search) => Object.fromEntries(
    Object.entries(obj).filter(([k]) => normalize(k).includes(normalize(search)))
)
export function numToDirection(number) {
    if (number == 0) return "up"
    if (number == 1) return "down"
    if (number == 2) return "north"
    if (number == 3) return "south"
    if (number == 4) return "west"
    if (number == 5) return "east"
}

export function directionToNum(direction) {
    if (direction === "up" || direction === "above") return 0;
    if (direction === "down" || direction === "below") return 1;
    if (direction === "north") return 2;
    if (direction === "south") return 3;
    if (direction === "west") return 4;
    if (direction === "east") return 5;
}

export function loadInv(itemData) {
    if (!itemData?.typeId) return null;
    const item = new mc.ItemStack(itemData?.typeId, itemData?.amount)
    item.nameTag = itemData?.nameTag;
    item.setLore(itemData?.lore);
    item.setCanDestroy(itemData?.canDestroy);
    item.setCanPlaceOn(itemData?.canPlaceOn);
    if (itemData?.damage)
        item.getComponent('durability').damage = itemData?.damage;
    itemData?.enchantments?.forEach(({ type, level }) => {
        const ench = new mc.EnchantmentType(type.id);
        item.getComponent('enchantable')?.addEnchantment({ type: ench, level });
    });
    itemData?.dynamicProperties.forEach(([id, value]) => item.setDynamicProperty(id, value));
    return item;
}

export function serializeItem(item) {
    return {
        typeId: item?.typeId,
        amount: item?.amount,
        lore: item?.getLore(),
        nameTag: item?.nameTag,
        lockMode: item?.lockMode,
        keepOnDeath: item?.keepOnDeath,
        canDestroy: item?.getCanDestroy(),
        canPlaceOn: item?.getCanDestroy(),
        damage: item?.getComponent('durability')?.damage,
        enchantments: item?.getComponent('enchantable')?.getEnchantments(),
        dynamicProperties: item?.getDynamicPropertyIds().map(id => ([id, item.getDynamicProperty(id)])),
    };
}

export function directionToRotation(direction) {
    if (direction === "north") return 0;
    if (direction === "south") return 180;
    if (direction === "west") return 90;
    if (direction === "east") return 270;
    if (direction === "up") return 90;
    if (direction === "down") return 270;
}

export function invertUpDown(face) {
    if (face == 'below') return 'above'; else
        if (face == 'above') return 'below'; else
            if (face == 'up') return 'down'; else
                if (face == 'down') return 'up'; else return face
}

export function includesAny(str, arr) {
    return arr.some(subStr => str.includes(subStr));
}
export function createDashedLine(viewDirection, playerPosition, numSegments, segmentLength, segmentStart) {
    const directionMagnitude = Math.sqrt(viewDirection.x * viewDirection.x + viewDirection.y * viewDirection.y + viewDirection.z * viewDirection.z)
    viewDirection.x /= directionMagnitude
    viewDirection.y /= directionMagnitude
    viewDirection.z /= directionMagnitude
    let points = []
    for (let i = segmentStart; i < numSegments; i++) {
        let distance = i * segmentLength
        let point = {
            x: playerPosition.x + viewDirection.x * distance,
            y: playerPosition.y + viewDirection.y * distance,
            z: playerPosition.z + viewDirection.z * distance
        }
        points.push(point)
    }
    return points
}
export function addVectors(v1, v2) {
    return { x: v1.x + v2.x, y: v1.y + v2.y, z: v1.z + v2.z };
}
export function divideVectorBy(vector, times) {
    return { x: vector.x / times, y: vector.y / times, z: vector.z / times };
}
export function rotateVector(vector, times) {
    const rotations = times % 4
    let { x, y, z } = vector
    for (let i = 0; i < rotations; i++) {
        [x, z] = [z, -x]
    }
    return { x, y, z };
}
export function relativeToAbsolute(base, relative) {
    return {
        x: base.x + relative.x,
        y: base.y + relative.y,
        z: base.z + relative.z
    };
}

export function getDirection(vectorA, vectorB) {
    const direction = {
        x: vectorB.x - vectorA.x,
        y: vectorB.y - vectorA.y,
        z: vectorB.z - vectorA.z
    };

    const magnitude = Math.sqrt(direction.x ** 2 + direction.y ** 2 + direction.z ** 2);

    return {
        x: direction.x / magnitude,
        y: direction.y / magnitude,
        z: direction.z / magnitude
    };
}
export function blockFloorCenter(block) {
    return { x: block.center().x, y: block.location.y, z: block.center().z }
}
export function operationWithVectorPLUS(vector, x, y, z) {
    let newVector = { x: vector.x + x, y: vector.y - 0.4, z: vector.z + z }
    if (newVector) return newVector
}
export function operationWithVectorMINUS(vector, x, y, z) {
    let newVector = { x: vector.x - x, y: vector.y - 0.4, z: vector.z - z }
    if (newVector) return newVector
}
export function trueFace(block, face) {
    const state = block?.permutation?.getState("minecraft:cardinal_direction")
    if (state) {
        if (state == 'north') {
            if (face == 'north') return 'north'; else
                if (face == 'south') return 'south'; else
                    if (face == 'west') return 'west'; else
                        if (face == 'east') return 'east'; else return face
        } else
            if (state == 'west') {
                if (face == 'north') return 'east'; else
                    if (face == 'south') return 'west'; else
                        if (face == 'west') return 'north'; else
                            if (face == 'east') return 'south'; else return face
            } else
                if (state == 'south') {
                    if (face == 'north') return 'south'; else
                        if (face == 'south') return 'north'; else
                            if (face == 'west') return 'east'; else
                                if (face == 'east') return 'west'; else return face
                } else
                    if (state == 'east') {
                        if (face == 'north') return 'west'; else
                            if (face == 'south') return 'east'; else
                                if (face == 'west') return 'south'; else
                                    if (face == 'east') return 'north'; else return face
                    }
    } else return face
}

export function convergeDirection(direction) {
    if (direction == 'north') return 'north'; else
        if (direction == 'south') return 'north'; else
            if (direction == 'west') return 'west'; else
                if (direction == 'east') return 'west'; else
                    if (direction == 'up') return 'up'; else
                        if (direction == 'down') return 'up'; else
                            if (direction == 'above') return 'above'; else
                                if (direction == 'below') return 'above'; else direction

}
export function itemIsBlock(block, item) {
    if (
        item?.typeId == 'minecraft:bedrock'
    ) {
        return true
    } else
        if (
            item?.typeId?.includes("kelp") && !item?.typeId == 'minecraft:dried_kelp_block' ||
            item?.typeId?.includes("coral") && !item?.typeId?.includes("block") ||
            item?.typeId?.includes("vine") ||
            item?.typeId?.includes("glowstone_dust") ||
            item?.typeId?.includes("hopper") ||
            item?.typeId?.includes("chain") ||
            item?.typeId?.includes("dripstone") ||
            item?.typeId == "minecraft:bamboo" ||
            item?.typeId?.includes("candle") ||
            item?.typeId?.includes("campfire") ||
            item?.typeId?.includes("cauldron") ||
            item?.typeId?.includes("armor_stand") ||
            item?.typeId?.includes("sign") ||
            item?.typeId?.includes("item_frame") ||
            item?.typeId?.includes("painting") ||
            item?.typeId?.includes("mushroom") ||
            item?.typeId?.includes("bell") ||
            item?.typeId?.includes("rail") ||
            item?.typeId?.includes("shovel") ||
            item?.typeId?.includes("torch") ||
            item?.typeId?.includes("amethyst_cluster") ||
            item?.typeId?.includes("blud") ||
            item?.typeId?.includes("_door") ||
            item?.typeId?.includes("ladder") ||
            item?.typeId?.includes("iron_bars") ||
            item?.typeId?.includes("bed") ||
            item?.typeId == "minecraft:bamboo" ||
            item?.typeId == "minecraft:lantern" ||
            item?.typeId == "minecraft:soul_lantern" ||
            item?.typeId == "minecraft:deadbush" ||
            item?.typeId == "minecraft:sniffer_egg" ||
            item?.typeId?.includes("sea_pickle") ||
            item?.typeId?.includes("brewing_stand") ||
            item?.typeId?.includes("frame") ||
            item?.typeId?.includes("tripwire_hook") ||
            item?.typeId?.includes("minecraft:lever") ||
            item?.typeId?.includes("amethyst") && !item?.typeId?.includes("_block") ||
            item?.typeId?.includes("poppy") ||
            item?.typeId?.includes("sapling") ||
            item?.typeId?.includes("vtng_btn:fake_") ||
            item?.typeId?.includes("propagule") ||
            item?.typeId?.includes("flower_pot") || item?.typeId?.includes("resin_clump") ||
            item?.typeId?.includes("waterlily") ||
            item?.typeId == 'minecraft:kelp' ||
            item?.typeId?.includes("seagrass") ||
            item?.typeId?.includes("glow_lichen") ||
            item?.typeId?.includes("pale_hanging_moss") ||
            item?.typeId?.includes("frog_spawn") ||
            item?.typeId?.includes("eyeblossom") ||
            item?.typeId?.includes("_fungus") ||
            item?.typeId?.includes("short_grass") ||
            item?.typeId?.includes("tall_grass") ||
            item?.typeId?.includes("nether_sprouts") ||
            item?.typeId?.includes("fern") ||
            item?.typeId?.includes("minecraft:web")
        ) {
            return false
        } else {
            try {
                if (item?.typeId?.includes("_skull") || item?.typeId?.includes("_head")) return true;
                if (block.dimension.runCommand(`setblock ${block.x} -64 ${block.z} ${item?.typeId} replace`).successCount > 0) {
                    block.dimension.runCommand(`setblock ${block.x} -64 ${block.z} bedrock replace`)
                    return true;
                } else {
                    return false;
                }
            } catch (error) {
                return false;
            }
        }
}
export function transferItem(containerA, containerB, i, amountRequested) {
    const itemA = containerA?.getItem(i)
    if (itemA && itemA?.amount >= amountRequested) {
        let hasSpace = false
        if (containerB.emptySlotsCount > 0) hasSpace = true; else
            for (let o = 0; o < containerB.size; o++) {
                const containerItem = containerB.getItem(o)
                if (containerItem?.isStackableWith(playerItem) && containerItem.amount + amountRequested <= containerItem.maxAmount) {
                    hasSpace = true
                }
            }
        if (hasSpace) {
            if (itemA.amount > amountRequested) {
                itemA.amount -= amountRequested
                containerA.setItem(i, itemA)
                itemA.amount = amountRequested
                containerB.addItem(itemA)
            } else
                if (itemA.amount == amountRequested) {
                    containerA.setItem(i,)
                    itemA.amount = amountRequested
                    containerB.addItem(itemA)
                }
        }
    }
}
export function transferEntityItem(entityItem, containerB, amountRequested) {
    const itemA = entityItem.getComponent('minecraft:item').itemStack
    if (itemA && itemA?.amount >= amountRequested) {
        let hasSpace = false
        if (containerB?.emptySlotsCount > 0) hasSpace = true; else
            for (let o = 0; o < containerB?.size; o++) {
                const containerItem = containerB.getItem(o)
                if (containerItem?.isStackableWith(itemA) && containerItem.amount + amountRequested <= containerItem.maxAmount) {
                    hasSpace = true
                }
            }
        if (hasSpace) {
            if (itemA.amount > amountRequested) {
                const itemfudido = entityItem.dimension.spawnItem(new mc.ItemStack(itemA?.typeId, itemA.amount - amountRequested), entityItem.location)
                itemfudido.teleport(itemfudido.location)
                itemA.amount = amountRequested
                entityItem?.remove()
                containerB.addItem(itemA)
            } else
                if (itemA.amount == amountRequested) {
                    entityItem.remove()
                    itemA.amount = amountRequested
                    containerB.addItem(itemA)
                }
        }
    }
}