import { Direction, EquipmentSlot, ItemStack, system, world } from "@minecraft/server";
import { damageTool, getFarmlandBlocks, getPlayerEquipment, getShovelableBlocks, getSilkTouchLevel, getUnbreakableVanillaBlocksIds, getWoodList, getWouldNotWantToBreak } from "../utils/my_API";
import { OreLootCollection } from "./definitions";
world.beforeEvents.playerBreakBlock.subscribe(event => {
    onPlayerBreakBlock(event);
});
world.beforeEvents.itemUseOn.subscribe(event => {
    onItemUseOn(event);
});
world.afterEvents.entityHitBlock.subscribe(event => {
    incorrectExtractionWarning(event);
});
export function getBlockTags(block) {
    const vanillaOreTags = Object.freeze({
        "minecraft:coal_ore": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:deepslate_coal_ore": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:quartz_ore": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:nether_gold_ore": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        //
        "minecraft:copper_ore": ["nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:deepslate_copper_ore": ["nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:lapis_ore": ["nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:deepslate_lapis_ore": ["nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:iron_ore": ["nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:deepslate_iron_ore": ["nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        //
        "minecraft:gold_ore": ["nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:deepslate_gold_ore": ["nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:diamond_ore": ["nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:deepslate_diamond_ore": ["nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:emerald_ore": ["nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:deepslate_emerald_ore": ["nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:redstone_ore": ["nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:deepslate_redstone_ore": ["nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        //
        "minecraft:ancient_debris": ["nps_mot:diamond_pick_diggable"],
    });
    const blockTags = [
        ...(vanillaOreTags[block.typeId] || []),
        ...(block.getTags() || [])
    ].filter(tags => tags && tags.length > 0);
    return blockTags;
}
export function getPickaxeTags(itemStack) {
    const vanillaPickaxeTags = Object.freeze({
        "minecraft:wooden_pickaxe": ["nps_mot:wood_pick_diggable"],
        "minecraft:stone_pickaxe": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable"],
        "minecraft:golden_pickaxe": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable"],
        "minecraft:iron_pickaxe": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable"],
        "minecraft:diamond_pickaxe": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"],
        "minecraft:netherite_pickaxe": ["nps_mot:wood_pick_diggable", "nps_mot:stone_pick_diggable", "nps_mot:iron_pick_diggable", "nps_mot:diamond_pick_diggable"]
    });
    const pickaxeTags = [
        ...(vanillaPickaxeTags[itemStack.typeId] || []),
        ...(itemStack.getTags() || [])
    ].filter(tags => tags && tags.length > 0);
    return pickaxeTags;
}
export function getOreCategory(tags) {
    const tagCategoryMap = {
        "nps_mot:wooden_pick_diggable": 0,
        "nps_mot:stone_pick_diggable": 1,
        "nps_mot:iron_pick_diggable": 2,
        "nps_mot:diamond_pick_diggable": 3,
        "nps_mot:obsidian_pick_diggable": 4,
        "nps_mot:titanium_pick_diggable": 5,
        "nps_mot:tungsten_pick_diggable": 6,
        "nps_mot:red_diamond_pick_diggable": 7
    };
    let oreCategory = 7; // Default category
    let match = false;
    tags.forEach(tag => {
        if (tagCategoryMap.hasOwnProperty(tag)) {
            oreCategory = Math.min(oreCategory, tagCategoryMap[tag]);
            match = true;
        }
    });
    if (match) {
        return oreCategory;
    }
    else {
        return undefined;
    }
}
export function isMotHoe(itemStack) {
    if (itemStack === undefined) {
        return false;
    }
    const itemTags = itemStack.getTags() || [];
    return itemTags.includes('nps_mot:is_hoe');
}
export function isMotShovel(itemStack) {
    if (itemStack === undefined) {
        return false;
    }
    const itemTags = itemStack.getTags() || [];
    return itemTags.includes('nps_mot:is_shovel');
}
export function isMotAxe(itemStack) {
    if (itemStack === undefined) {
        return false;
    }
    const itemTags = itemStack.getTags() || [];
    return itemTags.includes('nps_mot:is_axe');
}
export function isMotSword(itemStack) {
    if (itemStack === undefined) {
        return false;
    }
    const itemTags = itemStack.getTags() || [];
    return itemTags.includes('nps_mot:is_sword');
}
export function isMotHammer(itemStack) {
    if (itemStack === undefined) {
        return false;
    }
    const itemTags = itemStack.getTags() || [];
    return itemTags.includes('nps_mot:is_hammer');
}
export function isMotPickaxe(itemStack) {
    if (itemStack === undefined) {
        return false;
    }
    const itemTags = itemStack.getTags() || [];
    return itemTags.includes('nps_mot:is_pickaxe');
}
export function isVanillaPickaxe(itemStack) {
    if (itemStack === undefined) {
        return false;
    }
    const pickaxeList = [
        "minecraft:wooden_pickaxe",
        "minecraft:stone_pickaxe",
        "minecraft:iron_pickaxe",
        "minecraft:golden_pickaxe",
        "minecraft:diamond_pickaxe",
        "minecraft:netherite_pickaxe"
    ];
    return pickaxeList.includes(itemStack.typeId);
}
function onItemUseOn(event) {
    const block = event.block;
    const player = event.source;
    const playerEquipment = getPlayerEquipment(player);
    const mainhandItemstack = playerEquipment.getEquipment(EquipmentSlot.Mainhand);
    if (mainhandItemstack === undefined) {
        return;
    }
    if (block === undefined) {
        return;
    }
    if (isMotHoe(mainhandItemstack)) {
        if (getFarmlandBlocks().includes(block.typeId)) {
            if (block.typeId != "minecraft:dirt_with_roots") {
                system.run(() => {
                    player.playSound("hit.gravel", { location: block.location });
                    player.dimension.runCommand(`setblock ${block.location.x} ${block.location.y} ${block.location.z} minecraft:farmland`);
                    damageTool(player);
                });
            }
            else {
                system.run(() => {
                    player.playSound("hit.gravel", { location: block.location });
                    player.dimension.runCommand(`setblock ${block.location.x} ${block.location.y} ${block.location.z} minecraft:dirt`);
                    player.dimension.spawnItem(new ItemStack("minecraft:hanging_roots"), block.location);
                    damageTool(player);
                });
            }
        }
    }
    if (isMotShovel(mainhandItemstack)) {
        if (getShovelableBlocks().includes(block.typeId)) {
            if (block.typeId != "minecraft:snow_layer") {
                system.run(() => {
                    player.playSound("hit.grass", { location: block.location });
                    player.dimension.runCommand(`setblock ${block.location.x} ${block.location.y} ${block.location.z} minecraft:grass_path`);
                    damageTool(player);
                });
            }
            else {
                system.run(() => {
                    player.playSound("hit.grass", { location: block.location });
                    player.dimension.runCommand(`setblock ${block.location.x} ${block.location.y} ${block.location.z} air destroy`);
                    damageTool(player);
                });
            }
        }
    }
    if (isMotAxe(mainhandItemstack)) {
        if (getWoodList().includes(block.typeId)) {
            if (block.typeId !== undefined) {
                system.run(() => {
                    player.playSound("hit.wood", { location: block.location });
                    const logConversionTable = {
                        "minecraft:oak_log": "minecraft:stripped_oak_log",
                        "minecraft:spruce_log": "minecraft:stripped_spruce_log",
                        "minecraft:birch_log": "minecraft:stripped_birch_log",
                        "minecraft:jungle_log": "minecraft:stripped_jungle_log",
                        "minecraft:acacia_log": "minecraft:stripped_acacia_log",
                        "minecraft:dark_oak_log": "minecraft:stripped_dark_oak_log",
                        "minecraft:mangrove_log": "minecraft:stripped_mangrove_log",
                        "minecraft:cherry_log": "minecraft:stripped_cherry_log",
                        "minecraft:warped_stem": 'minecraft:stripped_warped_stem',
                        "minecraft:crimson_stem": "minecraft:stripped_crimson_stem",
                        "minecraft:bamboo_block": "minecraft:stripped_bamboo_block"
                    };
                    const tripWoodId = logConversionTable[block.typeId];
                    if (tripWoodId === undefined) {
                        return;
                    }
                    const pillar_axis = block.permutation.getState("pillar_axis");
                    player.dimension.runCommand(`setblock ${block.location.x} ${block.location.y} ${block.location.z} ${tripWoodId} ["pillar_axis"= "${pillar_axis}"]`);
                    damageTool(player);
                });
            }
        }
    }
}
export function hasMatchingTag(blockTags, pickaxeTags) {
    if (blockTags === undefined) {
        return false;
    }
    if (pickaxeTags === undefined) {
        return false;
    }
    for (const blockTag of blockTags) {
        if (pickaxeTags.includes(blockTag)) {
            return true;
        }
    }
    return false;
}
function onPlayerBreakBlock(event) {
    if (event.itemStack === undefined) {
        return;
    }
    const itemStack = event.itemStack;
    const player = event.player;
    const isHammer = isMotHammer(itemStack);
    if (isHammer == true) {
        onHammerMining(event);
        return;
    }
    const isPickaxe = isVanillaPickaxe(itemStack) || isMotPickaxe(itemStack);
    if (isPickaxe == true) {
        onPickaxeMining(event);
        return;
    }
    if (isMotAxe(itemStack)) {
        system.run(() => { damageTool(player); });
    }
    if (isMotShovel(itemStack)) {
        system.run(() => { damageTool(player); });
    }
    if (isMotSword(itemStack)) {
        system.run(() => { damageTool(player); });
    }
    if (isMotHoe(itemStack)) {
        system.run(() => { damageTool(player); });
    }
}
function incorrectExtractionWarning(event) {
    if (event.damagingEntity.typeId !== "minecraft:player") {
        return;
    }
    const player = event.damagingEntity;
    const itemStack = getPlayerEquipment(player).getEquipment(EquipmentSlot.Mainhand);
    if (itemStack === undefined) {
        return;
    } //we don't have any blocks that can be broken by hand, so we can return
    const block = event.hitBlock;
    const oreLootIndex = OreLootCollection.findOreIndexByOreId(block.typeId);
    const vanillaOreLootIndex = OreLootCollection.findVanillaOreIndexByOreId(block.typeId);
    if (oreLootIndex == -1 && vanillaOreLootIndex == -1) {
        return;
    }
    const pickaxeTags = getPickaxeTags(itemStack);
    const blockTags = getBlockTags(block);
    const hasTag = hasMatchingTag(blockTags, pickaxeTags);
    if (hasTag == false) {
        system.run(() => {
            player.onScreenDisplay.setActionBar({ translate: `nps_mot:incorrect_tool_extraction.yellow` });
        });
    }
}
function onPickaxeMining(event) {
    const block = event.block;
    const itemStack = event.itemStack;
    const player = event.player;
    //damageTool
    system.run(() => {
        damageTool(player);
    });
    //
    const oreIndex = OreLootCollection.findOreIndexByOreId(block.typeId);
    if (oreIndex == -1) {
        //block vanilla
        return;
    }
    //block mot
    const pickaxeTags = getPickaxeTags(itemStack);
    const blockTags = getBlockTags(block);
    const hasTag = hasMatchingTag(blockTags, pickaxeTags);
    if (hasTag == false) {
        system.run(() => {
            player.onScreenDisplay.setActionBar({ translate: `nps_mot:incorrect_tool_extraction.red` });
            player.playSound('nps_mot:fail', { location: player.location });
        });
        const silkTouchLevel = getSilkTouchLevel(itemStack);
        if (silkTouchLevel > 0) {
            event.cancel = true;
            system.run(() => {
                block.dimension.runCommand(`/setblock ${block.x} ${block.y} ${block.z} air`);
            });
        }
    }
    else {
        const location = block.bottomCenter();
        OreLootCollection.ores[oreIndex].dropLoot({
            dimension: block.dimension,
            x: location.x,
            y: location.y,
            z: location.z
        }, itemStack, true);
    }
}
function getHammerBlocksToBreak(event) {
    const player = event.player;
    const block = event.block;
    const blockFromViewDirection = player.getBlockFromViewDirection();
    let face = undefined;
    if (blockFromViewDirection !== undefined) {
        face = blockFromViewDirection.face;
    }
    let blocksToBreak = [];
    switch (face) {
        case Direction.Down:
        case Direction.Up: {
            //x,z
            for (let x = -1; x <= 1; x++) {
                for (let z = -1; z <= 1; z++) {
                    //if(x == 0 && z == 0){continue;}
                    const blockToCheck = player.dimension.getBlock({
                        x: block.x + x,
                        y: block.y,
                        z: block.z + z
                    });
                    blocksToBreak.push(blockToCheck);
                }
            }
            break;
        }
        case Direction.East:
        case Direction.West: {
            //z,y
            for (let z = -1; z <= 1; z++) {
                for (let y = -1; y <= 1; y++) {
                    //if(y == 0 && z == 0){continue;}
                    if ((block.y + y) < block.dimension.heightRange.min || (block.y + y) > block.dimension.heightRange.max) {
                        continue;
                    }
                    const blockToCheck = player.dimension.getBlock({
                        x: block.x,
                        y: block.y + y,
                        z: block.z + z
                    });
                    blocksToBreak.push(blockToCheck);
                }
            }
            break;
        }
        case Direction.North:
        case Direction.South: {
            //x,y
            for (let x = -1; x <= 1; x++) {
                for (let y = -1; y <= 1; y++) {
                    //if(x == 0 && y == 0){continue;}
                    if ((block.y + y) < block.dimension.heightRange.min || (block.y + y) > block.dimension.heightRange.max) {
                        continue;
                    }
                    const blockToCheck = player.dimension.getBlock({
                        x: block.x + x,
                        y: block.y + y,
                        z: block.z
                    });
                    blocksToBreak.push(blockToCheck);
                }
            }
            break;
        }
    }
    return blocksToBreak;
}
function onHammerMining(event) {
    const itemStack = event.itemStack;
    const player = event.player;
    const block = event.block;
    //get the blocks to break
    const blocksToBreak = getHammerBlocksToBreak(event); // peut etre deplacer apres
    const exclusionBlockIds = [
        "minecraft:torch",
        "minecraft:redstone_torch",
        "minecraft:soul_torch"
    ];
    if (exclusionBlockIds.includes(block.typeId)) {
        return;
    }
    //check if block is valid
    let canBreakBlocks = false;
    const oreLootIndex = OreLootCollection.findOreIndexByOreId(block.typeId);
    if (oreLootIndex != -1) {
        //MOT block
        const pickaxeTags = getPickaxeTags(itemStack);
        const blockTags = getBlockTags(block);
        const hasTag = hasMatchingTag(blockTags, pickaxeTags);
        if (hasTag) {
            canBreakBlocks = true;
        }
        else {
            event.cancel = true;
            system.run(() => {
                block.dimension.runCommand(`/setblock ${block.x} ${block.y} ${block.z} air`);
            });
        }
    }
    const vanillaOreLootIndex = OreLootCollection.findVanillaOreIndexByOreId(block.typeId);
    if (vanillaOreLootIndex != -1) {
        //vanilla MOT
        const pickaxeTags = getPickaxeTags(itemStack);
        const blockTags = getBlockTags(block);
        const hasTag = hasMatchingTag(blockTags, pickaxeTags);
        if (hasTag) {
            canBreakBlocks = true;
        }
        else {
            event.cancel = true;
            system.run(() => {
                block.dimension.runCommand(`/setblock ${block.x} ${block.y} ${block.z} air`);
            });
        }
    }
    if (vanillaOreLootIndex == -1 && oreLootIndex == -1) {
        //vanilla block
        canBreakBlocks = true;
    }
    if (!canBreakBlocks) {
        //damageTool
        system.run(() => {
            damageTool(player);
        });
        return;
    }
    //break the blocks obtained
    const damage = 1 + breakBlocks(event, blocksToBreak, itemStack, player);
    //damage tool
    system.run(() => {
        damageTool(player, damage);
    });
}
function breakBlocks(event, blocks, itemStack, player) {
    let brokenBlock = 0;
    for (let i = 0; i < blocks.length; i++) {
        brokenBlock += breakBlock(event, blocks[i], itemStack, player);
    }
    return brokenBlock;
}
function breakBlock(event, block, itemStack, player) {
    if (getUnbreakableVanillaBlocksIds().includes(block.typeId)) {
        return 0;
    }
    if (getWouldNotWantToBreak().includes(block.typeId)) {
        return 0;
    }
    const oreLootIndex = OreLootCollection.findOreIndexByOreId(block.typeId);
    const vanillaOreLootIndex = OreLootCollection.findVanillaOreIndexByOreId(block.typeId);
    if (oreLootIndex == -1 && vanillaOreLootIndex == -1) {
        //vanilla block
        system.run(() => {
            block.dimension.runCommand(`/setblock ${block.x} ${block.y} ${block.z} air destroy`);
        });
        return 1;
    }
    if (vanillaOreLootIndex != -1) {
        const pickaxeTags = getPickaxeTags(itemStack);
        const blockTags = getBlockTags(block);
        const hasTag = hasMatchingTag(blockTags, pickaxeTags);
        if (hasTag) {
            event.cancel = true;
            const location = block.bottomCenter();
            OreLootCollection.vanillaOres[vanillaOreLootIndex].dropLoot({
                dimension: block.dimension,
                x: location.x,
                y: location.y,
                z: location.z
            }, itemStack, false);
            system.run(() => {
                block.dimension.runCommand(`/setblock ${block.x} ${block.y} ${block.z} air`);
            });
            return 1;
        }
        else {
            return 0;
        }
    }
    if (oreLootIndex != -1) {
        const pickaxeTags = getPickaxeTags(itemStack);
        const blockTags = getBlockTags(block);
        const hasTag = hasMatchingTag(blockTags, pickaxeTags);
        if (hasTag) {
            event.cancel = true;
            const location = block.bottomCenter();
            OreLootCollection.ores[oreLootIndex].dropLoot({
                dimension: block.dimension,
                x: location.x,
                y: location.y,
                z: location.z
            }, itemStack, false);
            system.run(() => {
                block.dimension.runCommand(`/setblock ${block.x} ${block.y} ${block.z} air`);
            });
            return 1;
        }
        else {
            return 0;
        }
    }
}
