import {
    BlockPermutation,
    DimensionTypes,
    Direction,
    EntityComponentTypes,
    EquipmentSlot,
    HudElement,
    HudVisibility,
    ItemStack,
    system,
    world
} from "@minecraft/server";
import {ActionFormData} from "@minecraft/server-ui";


world.afterEvents.playerSpawn.subscribe(checkTutorialBook);

function checkTutorialBook(event) {
    if (event.player.getDynamicProperty("owlscubed_pob:tutorialbook") !== undefined
        && event.player.getDynamicProperty("owlscubed_pob:tutorialbook") === "true") {
        return;
    }
    event.player.dimension.spawnItem(new ItemStack("owlscubed_pob:tutorial_book0", 1),
        event.player.location);
    event.player.setDynamicProperty("owlscubed_pob:tutorialbook", "true");
}

function playPageTurnSound(player) {
    player.playSound("item.book.page_turn");
}


world.afterEvents.itemUse.subscribe(pageTurnBookMinus);

function pageTurnBookMinus(event) {
    // console.error(event.itemStack.typeId)
    // placeElementsIn3DWorld(list, event.source.location, event.source);


    if (!event.source.isSneaking) {
        return;
    }

    const playerMainHandBoolean = event.source.getComponent(EntityComponentTypes.Equippable)
        .getEquipment(EquipmentSlot.Mainhand).typeId.startsWith("owlscubed_pob:tutorial_book");
    const playerMainHandTypeId = event.source.getComponent(EntityComponentTypes.Equippable)
        .getEquipment(EquipmentSlot.Mainhand).typeId;

    if (playerMainHandTypeId === undefined || !playerMainHandBoolean) {
        return;
    }


    playPageTurnSound(event.source);

    const currentTutorialBookPage = playerMainHandTypeId.replace(/^owlscubed_pob:tutorial_book/, '');
    let newTutorialBookPage = parseInt(currentTutorialBookPage) - 1;
    if (playerMainHandTypeId === "owlscubed_pob:tutorial_book0") {
        newTutorialBookPage = 13
    }


    event.source.getComponent(EntityComponentTypes.Equippable).setEquipment(EquipmentSlot.Mainhand,
        new ItemStack(`owlscubed_pob:tutorial_book${newTutorialBookPage}`));
}

world.afterEvents.itemUse.subscribe(pageTurnBookPlus);

function pageTurnBookPlus(event) {
    if (event.source.isSneaking) {
        return;
    }

    const playerMainHandBoolean = event.source.getComponent(EntityComponentTypes.Equippable)
        .getEquipment(EquipmentSlot.Mainhand).typeId.startsWith("owlscubed_pob:tutorial_book");
    const playerMainHandTypeId = event.source.getComponent(EntityComponentTypes.Equippable)
        .getEquipment(EquipmentSlot.Mainhand).typeId;

    if (playerMainHandTypeId === undefined || !playerMainHandBoolean) {
        return;
    }

    playPageTurnSound(event.source);

    const currentTutorialBookPage = playerMainHandTypeId.replace(/^owlscubed_pob:tutorial_book/, '');
    let newTutorialBookPage = parseInt(currentTutorialBookPage) + 1;
    if (playerMainHandTypeId === "owlscubed_pob:tutorial_book13") {
        newTutorialBookPage = 0
    }

    event.source.getComponent(EntityComponentTypes.Equippable).setEquipment(EquipmentSlot.Mainhand,
        new ItemStack(`owlscubed_pob:tutorial_book${newTutorialBookPage}`));
}

//----------------------------------------------------------------------------------------------------------------------
//CREATE magma damage
world.beforeEvents.worldInitialize.subscribe(initEvent => {
    initEvent.blockComponentRegistry.registerCustomComponent('owlscubed_pob:magma_component_onStepOn', {
        onStepOn: event => {
            magmaStepOn(event)
        },
    });
});

world.beforeEvents.worldInitialize.subscribe(initEvent => {
    initEvent.blockComponentRegistry.registerCustomComponent('owlscubed_pob:magma_component_onStepOff', {
        onStepOff: event => {
            magmaStepOff(event)
        },
    });
});

const magmaDamageEntities = new Map();

function magmaStepOn(event) {
    const entityId = event.entity.id
    let locations = new Set([]);

    if (magmaDamageEntities.has(entityId)) {
        locations = magmaDamageEntities.get(entityId)
    }
    locations.add(JSON.stringify(event.block.location));
    magmaDamageEntities.set(entityId, locations);
}

function magmaStepOff(event) {
    try {
        const entityId = event.entity.id
        let locations = magmaDamageEntities.get(entityId);
        locations.delete(JSON.stringify(event.block.location));
        magmaDamageEntities.set(entityId, locations);
    } catch (e) {
    }
}

system.runInterval(checkEntitiesForDamage, 2);

function checkEntitiesForDamage() {
    for (const [entityId, locations] of magmaDamageEntities) {
        if (locations.size !== 0) {
            try {
                if (world.getEntity(entityId).typeId === "minecraft:player") {
                    if (!world.getEntity(entityId).isSneaking) {
                        world.getEntity(entityId).applyDamage(1)
                    }
                } else {
                    world.getEntity(entityId).applyDamage(1)
                }
            } catch (error) {
                magmaDamageEntities.delete(entityId)
            }
        } else {
            magmaDamageEntities.delete(entityId)
        }
    }
}

const magmaList = new Set(["owlscubed_pob:simple_blocks_logic-main-v10_h14",
    "owlscubed_pob:simple_blocks_logic-main-v10_h13",
    "owlscubed_pob:simple_blocks_logic-main-v10_h12",
    "owlscubed_pob:column_blocks_logic-main-v21_h7"])

system.runInterval(additionalCheck, 10);

function additionalCheck() {
    world.getPlayers().forEach(player => {
        const entityId = player.id
        if (magmaDamageEntities.get(entityId) === undefined) {
            return
        }
        const dimension = player.dimension
        const locations = magmaDamageEntities.get(entityId)
        for (const location of locations) {
            const block = dimension.getBlock(JSON.parse(location))
            if (!magmaList.has(block.typeId)) {
                locations.delete(JSON.stringify(block.location))
                magmaDamageEntities.set(entityId, locations)
            }
        }
    });
}


//----------------------------------------------------------------------------------------------------------------------
//CREATE pale_carved_pumpkin with shears
world.beforeEvents.worldInitialize.subscribe(initEvent => {
    initEvent.blockComponentRegistry.registerCustomComponent('owlscubed_pob:pale_pumpkin_onPlayerInteract', {
        onPlayerInteract: event => {
            const playerMainHandTypeId = event.player.getComponent(EntityComponentTypes.Equippable)
                .getEquipment(EquipmentSlot.Mainhand).typeId;
            if (playerMainHandTypeId !== "minecraft:shears") {
                return
            }
            let cardinalDirection
            switch (event.face) {
                case Direction.North:
                    cardinalDirection = "north"
                    break;
                case Direction.West:
                    cardinalDirection = "west"
                    break;
                case Direction.East:
                    cardinalDirection = "east"
                    break;
                case Direction.South:
                    cardinalDirection = "south"
                    break;
                default:
                    cardinalDirection = "south";
            }
            const newBlockPermutation = BlockPermutation.resolve("owlscubed_pob:pale_carved_pumpkin", {"minecraft:cardinal_direction": cardinalDirection})
            event.dimension.setBlockPermutation(event.block.location, newBlockPermutation)
            event.dimension.playSound("pumpkin.carve", event.block.location)
        },
    });
});

//----------------------------------------------------------------------------------------------------------------------
//Open changelog menu
const lastChangeVersion = "1.3.2"

world.afterEvents.playerSpawn.subscribe(checkPropertyForOpenChangeLogMenu);

const playerPropertyId = "owlscubed_pob:changeLogProperty"

function checkPropertyForOpenChangeLogMenu(event) {
    const playerProperty = event.player.getDynamicProperty(playerPropertyId)

    if (playerProperty === undefined || playerProperty !== lastChangeVersion) {
        openChangeLogMenuAndSave(event.player, playerProperty)
    }


}

function openChangeLogMenuAndSave(player, playersProperty) {
    const form = new ActionFormData()
        .title({translate: 'owlscubed_pob:changeLogMenu.title'})
        .body({
            translate: 'owlscubed_pob:changeLogMenu.body',
            with: Array(100).fill("\n")
        })
        .button("Close ChangeLog")

    form.show(player).then(response => {
        if (response.cancelationReason === "UserBusy") {
            system.runTimeout(() => {
                openChangeLogMenuAndSave(player, playersProperty)
            }, 5);
        }
        player.setDynamicProperty(playerPropertyId, lastChangeVersion)
    });
}

//----------------------------------------------------------------------------------------------------------------------
//send typeid for player
world.afterEvents.itemUse.subscribe(sendTypeId);

function sendTypeId(event) {
    if (event.itemStack.typeId !== "owlscubed_pob:magnifier") {
        return
    }
    const player = event.source
    const block = event.source.getBlockFromViewDirection(
        {maxDistance: 50, includeLiquidBlocks: false, includePassableBlocks: false})?.block
    if (block === undefined) {
        player.sendMessage("We couldn't find a suitable block within a distance of 50 blocks.")
    } else {
        player.sendMessage("Block type id: " + block.typeId)
        console.error("Block type id: " + block.typeId)
    }
}

//----------------------------------------------------------------------------------------------------------------------
//lamp logic

const lampsOnPlayerInteractCache = {};

system.runInterval(lampsOnPlayerInteractCacheCleaner, 5);

function lampsOnPlayerInteractCacheCleaner() {
    for (const location in lampsOnPlayerInteractCache) {
        const ticks = lampsOnPlayerInteractCache[location];
        const result = system.currentTick - ticks;
        if (result > 200) {
            delete lampsOnPlayerInteractCache[location];
        }
    }
}

world.beforeEvents.worldInitialize.subscribe(initEvent => {
    initEvent.blockComponentRegistry.registerCustomComponent('owlscubed_pob:lamp_onPlayerInteract', {
        onPlayerInteract: event => {
            const location = event.block.location;
            lampsOnPlayerInteractCache[JSON.stringify(location)] = system.currentTick

            const lampOffTypeId = event.block.typeId
            const lampOnTypeId = lampsOn.get(lampOffTypeId)

            event.dimension.setBlockType(event.block.location, lampOnTypeId)
            event.dimension.playSound("block.click", event.block.center())
        },
    });
});


const lampsOnStepOnCache = {};

system.runInterval(lampsOnStepOnCacheCleaner, 5);

function lampsOnStepOnCacheCleaner() {
    for (const location in lampsOnStepOnCache) {
        const ticks = lampsOnStepOnCache[location];
        const result = system.currentTick - ticks;
        if (result > 40) {
            delete lampsOnStepOnCache[location];
        }
    }
}

world.beforeEvents.worldInitialize.subscribe(initEvent => {
    initEvent.blockComponentRegistry.registerCustomComponent('owlscubed_pob:lamp_onStepOn', {
        onStepOn: event => {
            if (event.entity.typeId !== "minecraft:player") {
                return
            }

            const location = event.block.location;
            lampsOnStepOnCache[JSON.stringify(location)] = system.currentTick

            const lampOffTypeId = event.block.typeId
            const lampOnTypeId = lampsOn.get(lampOffTypeId)

            event.dimension.setBlockType(event.block.location, lampOnTypeId)
        },
    });
});

world.beforeEvents.worldInitialize.subscribe(initEvent => {
    initEvent.blockComponentRegistry.registerCustomComponent('owlscubed_pob:lamp_onTick', {
        onTick: event => {
            const redstonePower = event.block.getRedstonePower()
            if (redstonePower === undefined || redstonePower === 0) {
                if (lampsOnStepOnCache[JSON.stringify(event.block.location)] === undefined
                    && lampsOnPlayerInteractCache[JSON.stringify(event.block.location)] === undefined) {
                    const lampOnTypeId = event.block.typeId
                    const lampOffTypeId = lampsOff.get(lampOnTypeId)
                    event.dimension.setBlockType(event.block.location, lampOffTypeId)
                }
            }
        },
    });
});

const lampsOff = new Map([
    ["owlscubed_pob:simple_blocks_logic-light_on-v1_h0", "owlscubed_pob:iron_horizontal_lamp"],
    ["owlscubed_pob:simple_blocks_logic-light_on-v1_h2", "owlscubed_pob:iron_lamp"],
    ["owlscubed_pob:simple_blocks_logic-light_on-v1_h1", "owlscubed_pob:iron_large_grid_lamp"],
    ["owlscubed_pob:simple_blocks_logic-light_on-v0_h0", "owlscubed_pob:redstone_decorative_lamp_#1"],
    ["owlscubed_pob:simple_blocks_logic-light_on-v0_h1", "owlscubed_pob:redstone_decorative_lamp_#2"],
    ["owlscubed_pob:simple_blocks_logic-light_on-v0_h2", "owlscubed_pob:redstone_decorative_lamp_#3"],
    ["owlscubed_pob:simple_blocks_logic-light_on-v1_h3", "owlscubed_pob:sea_horizontal_lamp"],
    ["owlscubed_pob:simple_blocks_logic-light_on-v1_h5", "owlscubed_pob:sea_lamp"],
    ["owlscubed_pob:simple_blocks_logic-light_on-v1_h4", "owlscubed_pob:sea_large_grid_lamp"],
]);
const lampsOn = new Map([
    ["owlscubed_pob:iron_horizontal_lamp", "owlscubed_pob:simple_blocks_logic-light_on-v1_h0"],
    ["owlscubed_pob:iron_lamp", "owlscubed_pob:simple_blocks_logic-light_on-v1_h2"],
    ["owlscubed_pob:iron_large_grid_lamp", "owlscubed_pob:simple_blocks_logic-light_on-v1_h1"],
    ["owlscubed_pob:redstone_decorative_lamp_#1", "owlscubed_pob:simple_blocks_logic-light_on-v0_h0"],
    ["owlscubed_pob:redstone_decorative_lamp_#2", "owlscubed_pob:simple_blocks_logic-light_on-v0_h1"],
    ["owlscubed_pob:redstone_decorative_lamp_#3", "owlscubed_pob:simple_blocks_logic-light_on-v0_h2"],
    ["owlscubed_pob:sea_horizontal_lamp", "owlscubed_pob:simple_blocks_logic-light_on-v1_h3"],
    ["owlscubed_pob:sea_lamp", "owlscubed_pob:simple_blocks_logic-light_on-v1_h5"],
    ["owlscubed_pob:sea_large_grid_lamp", "owlscubed_pob:simple_blocks_logic-light_on-v1_h4"],
]);


world.beforeEvents.worldInitialize.subscribe(initEvent => {
    initEvent.blockComponentRegistry.registerCustomComponent('owlscubed_pob:lamp_off_onTick', {
        onTick: event => {
            const redstonePower = event.block.getRedstonePower()
            if (redstonePower !== undefined && redstonePower !== 0) {

                const lampOffTypeId = event.block.typeId
                const lampOnTypeId = lampsOn.get(lampOffTypeId)
                event.dimension.setBlockType(event.block.location, lampOnTypeId)

            }
        },
    });
});

world.afterEvents.playerBreakBlock.subscribe(playerBreakLampOn);

function playerBreakLampOn(event) {
    const location = JSON.stringify(event.block.location)

    delete lampsOnStepOnCache[location];
    delete lampsOnPlayerInteractCache[location];

    if (!lampsOff.has(event.brokenBlockPermutation.type.id)) {
        return
    }

    if (event.player.getGameMode() === "creative") {
        return
    }

    const centerLocation = event.block.center()

    const itemStack = new ItemStack(lampsOff.get(event.brokenBlockPermutation.type.id), 1)

    event.dimension.spawnItem(itemStack, centerLocation)

}

//----------------------------------------------------------------------------------------------------------------------
//sit logic

const playerSitCache = {}

system.runInterval(playerSitCacheCleaner, 5);

function playerSitCacheCleaner() {
    for (const playerId in playerSitCache) {
        const ticks = playerSitCache[playerId];
        const result = system.currentTick - ticks;
        if (result > 5) {
            delete playerSitCache[playerId];
        }
    }
}

world.beforeEvents.playerInteractWithBlock.subscribe(playerSit);

function playerSit(event) {
    const {block, player} = event;
    if (!player.isSneaking) {
        return;
    }
    if (!(block.typeId.startsWith("owlscubed_pob") && block.typeId.endsWith("_slab"))) {
        return;
    }
    const equipment = player.getComponent('equippable');
    const mainhandItem = equipment.getEquipment('Mainhand');
    if (mainhandItem !== undefined) {
        return
    }

    const direction = block.permutation.getState("minecraft:block_face");
    if (direction !== "up" && direction !== "down") {
        return
    }
    switch (direction) {
        case 'up':
            system.runTimeout(() => {
                const aboveBlock = block.above(1)
                if (!playerSitCache[player.id] && aboveBlock.isAir) {
                    const spawnLocation = {x: block.center().x, y: block.center().y - 0.2, z: block.center().z}
                    const entity = block.dimension.spawnEntity('owlscubed_pob:sit', spawnLocation);
                    const component = entity.getComponent(EntityComponentTypes.Rideable)
                    component.addRider(player)
                    playerSitCache[player.id] = system.currentTick
                }
            }, 1);
            break;
        case 'down':
            system.runTimeout(() => {
                const aboveBlock = block.above(2)
                if (!playerSitCache[player.id] && aboveBlock.isAir) {
                    const spawnLocation = {x: block.center().x, y: block.center().y + 0.3, z: block.center().z}
                    const entity = block.dimension.spawnEntity('owlscubed_pob:sit', spawnLocation);
                    const component = entity.getComponent(EntityComponentTypes.Rideable)
                    component.addRider(player)
                    playerSitCache[player.id] = system.currentTick
                }
            }, 1);
            break;
    }
}


system.runInterval(playerSitChecker, 1);

function playerSitChecker() {
    world.getPlayers().forEach(player => {
        const component = player.getComponent(EntityComponentTypes.Riding)
        if (component === undefined) {
            player.onScreenDisplay.setHudVisibility(HudVisibility.Reset, [HudElement.HorseHealth])
            return
        }
        const entity = component.entityRidingOn
        if (entity.typeId === "owlscubed_pob:sit") {
            player.onScreenDisplay.setHudVisibility(HudVisibility.Hide, [HudElement.HorseHealth])
        } else {
            player.onScreenDisplay.setHudVisibility(HudVisibility.Reset, [HudElement.HorseHealth])
        }
    });
}

system.runInterval(sitEntityChecker, 1);

function sitEntityChecker() {
    const dimensions = DimensionTypes.getAll()
    for (let dimension of dimensions) {
        const entities = world.getDimension(dimension.typeId).getEntities({
            type: "owlscubed_pob:sit"
        })
        for (const entity of entities) {
            const entityRideableComp = entity.getComponent(EntityComponentTypes.Rideable);
            const riders = entityRideableComp.getRiders()

            if (riders.length === 0) {
                entity.remove()
            } else {
                const player = riders[0]
                const rotation = player.getRotation()
                entity.tryTeleport(entity.location, {
                    rotation: rotation
                })
            }
        }
    }
}