import { EquipmentSlot, EntityEquippableComponent, GameMode } from '@minecraft/server';
import { blockToKey, highlightBlock, highlightBlockTall, itemManager } from '../sgs_farm_lib';
import * as mc from "@minecraft/server";

export class fenceManager {
    static beforeplace(data) {
        const block = data.block;

        const north = block.north();
        const east = block.east();
        const south = block.south();
        const west = block.west();

        const northConnects = (north.hasTag("sgs_farm_fence"));
        const eastConnects = (east.hasTag("sgs_farm_fence"));
        const southConnects = (south.hasTag("sgs_farm_fence"));
        const westConnects = (west.hasTag("sgs_farm_fence"));

        mc.system.runTimeout(() => {
            if (northConnects && !north.hasTag("sgs_farm_gate")) updatePermutation(north, 'sgs_farm:fence_south', 1);
            if (eastConnects && !east.hasTag("sgs_farm_gate")) updatePermutation(east, 'sgs_farm:fence_west', 1);
            if (southConnects && !south.hasTag("sgs_farm_gate")) updatePermutation(south, 'sgs_farm:fence_north', 1);
            if (westConnects && !west.hasTag("sgs_farm_gate")) updatePermutation(west, 'sgs_farm:fence_east', 1);
        }, 0)

        if (data.permutationToPlace.getState('sgs_farm:fence_inventory') == undefined)  //U3 Update compat for item_visual
        {
            data.permutationToPlace = mc.BlockPermutation.resolve(data.permutationToPlace.type.id, { 'sgs_farm:fence_north': northConnects ? 1 : 0, 'sgs_farm:fence_south': southConnects ? 1 : 0, 'sgs_farm:fence_east': eastConnects ? 1 : 0, 'sgs_farm:fence_west': westConnects ? 1 : 0 });
            return;
        }
        data.permutationToPlace = mc.BlockPermutation.resolve(data.permutationToPlace.type.id, { 'sgs_farm:fence_inventory': 1, 'sgs_farm:fence_north': northConnects ? 1 : 0, 'sgs_farm:fence_south': southConnects ? 1 : 0, 'sgs_farm:fence_east': eastConnects ? 1 : 0, 'sgs_farm:fence_west': westConnects ? 1 : 0 });
    }

    static updatePermutation(block, state, number) {
        block.setPermutation(block.permutation.withState(state, number));

        if (block.above().hasTag("sgs_farm_fence_hitbox")) {
            const above = block.above();
            above.setPermutation(above.permutation.withState(state, number));
        }
    }

    static destroy(data) {

        const northConnects = data.destroyedBlockPermutation.getState("sgs_farm:fence_north");
        const eastConnects = data.destroyedBlockPermutation.getState("sgs_farm:fence_east");
        const southConnects = data.destroyedBlockPermutation.getState("sgs_farm:fence_south");
        const westConnects = data.destroyedBlockPermutation.getState("sgs_farm:fence_west");



        try {
            const block = data.block;
            const north = block.north();
            const east = block.east();
            const south = block.south();
            const west = block.west();

            mc.world.setDynamicProperty(blockToKey(block), undefined);
            if (northConnects && north.hasTag("sgs_farm_fence") && !north.hasTag("sgs_farm_gate")) updatePermutation(north, 'sgs_farm:fence_south', 0);
            if (eastConnects && east.hasTag("sgs_farm_fence") && !east.hasTag("sgs_farm_gate")) updatePermutation(east, 'sgs_farm:fence_west', 0);
            if (southConnects && south.hasTag("sgs_farm_fence") && !south.hasTag("sgs_farm_gate")) updatePermutation(south, 'sgs_farm:fence_north', 0);
            if (westConnects && west.hasTag("sgs_farm_fence") && !west.hasTag("sgs_farm_gate")) updatePermutation(west, 'sgs_farm:fence_east', 0);

        } catch (error) { };
    }

    static beforeplaceGate(data) {
        const block = data.block;

        const north = block.north();
        const east = block.east();
        const south = block.south();
        const west = block.west();

        const northConnects = (north.hasTag("sgs_farm_fence"));
        const eastConnects = (east.hasTag("sgs_farm_fence"));
        const southConnects = (south.hasTag("sgs_farm_fence"));
        const westConnects = (west.hasTag("sgs_farm_fence"));

        mc.system.runTimeout(() => {
            if (northConnects && !north.hasTag("sgs_farm_gate")) updatePermutation(north, 'sgs_farm:fence_south', 1);
            if (eastConnects && !east.hasTag("sgs_farm_gate")) updatePermutation(east, 'sgs_farm:fence_west', 1);
            if (southConnects && !south.hasTag("sgs_farm_gate")) updatePermutation(south, 'sgs_farm:fence_north', 1);
            if (westConnects && !west.hasTag("sgs_farm_gate")) updatePermutation(west, 'sgs_farm:fence_east', 1);
        }, 0)

    }

    static interactGate(block, player) {
        const currentState = block.permutation.getState('sgs_farm:open');
        const newOpenState = !currentState;
        const sound = newOpenState ? 'open.fence_gate' : 'close.fence_gate';

        const rotationAngle = player.getRotation().y;
        const openSouth = block.permutation.getState('minecraft:cardinal_direction') != directionDisplay(rotationAngle);

        const newPermutation = mc.BlockPermutation.resolve(block.typeId, {
            ...block.permutation.getAllStates(),
            'sgs_farm:open': newOpenState,
            'sgs_farm:open_south': openSouth
        });

        block.setPermutation(newPermutation);
        block.dimension.playSound(sound, block.location);

        //update top hitbox
        const up = block.above();
        if (up.type.id == "sgs_farm:dec_gate_hitbox") {
            const newPermutation = mc.BlockPermutation.resolve(up.typeId, {
                ...up.permutation.getAllStates(),
                'sgs_farm:open': newOpenState,
                'sgs_farm:open_south': openSouth
            });
            up.setPermutation(newPermutation);
            return;
        }
    }

    static destroyGate(data) {
        try {
            const block = data.block;
            const north = block.north();
            const east = block.east();
            const south = block.south();
            const west = block.west();

            mc.world.setDynamicProperty(blockToKey(block), undefined);
            if (north.hasTag("sgs_farm_fence") && !north.hasTag("sgs_farm_gate")) updatePermutation(north, 'sgs_farm:fence_south', 0);
            if (east.hasTag("sgs_farm_fence") && !east.hasTag("sgs_farm_gate")) updatePermutation(east, 'sgs_farm:fence_west', 0);
            if (south.hasTag("sgs_farm_fence") && !south.hasTag("sgs_farm_gate")) updatePermutation(south, 'sgs_farm:fence_north', 0);
            if (west.hasTag("sgs_farm_fence") && !west.hasTag("sgs_farm_gate")) updatePermutation(west, 'sgs_farm:fence_east', 0);

        } catch (error) { };
    }
}

function directionDisplay(angle) {
    if (Math.abs(angle) > 112.5) return 'north';
    if (Math.abs(angle) < 67.5) return 'south';
    if (angle < 157.5 && angle > 22.5) return 'west';
    if (angle > -157.5 && angle < -22.5) return 'east';
    return '';
}

toggleHitboxListener()

function toggleHitboxListener() {
    mc.world.beforeEvents.playerInteractWithBlock.subscribe((data) => {
        const { block, player, itemStack } = data;

        if (itemStack == undefined) return;
        if (itemStack.hasTag("minecraft:is_axe") && block.hasTag("sgs_farm_gate")) {
            data.cancel = true;
            mc.system.runTimeout(() => {
                toggleHitboxGate(block, player, itemStack);
            }, 1)
            return;
        }

        if (itemStack.hasTag("minecraft:is_axe") && block.hasTag("sgs_farm_fence")) {
            if (player.isSneaking) {
                data.cancel = true;

                const mode = checkConnectionMode(block);
                mc.system.runTimeout(() => {
                    setConnectionMode(block, mode + 1, player);
                }, 1)
                return;
            }
            else {
                data.cancel = true;
                mc.system.runTimeout(() => {
                    toggleHitbox(block, player, itemStack);
                }, 1)
                return;
            }
        }
    });
}

function toggleHitbox(block, player, item) {

    const up = block.above();

    if (up.isAir) {
        player.onScreenDisplay.setActionBar("§6[Fence]§f Hitbox 1.5");
        up.setPermutation(mc.BlockPermutation.resolve("sgs_farm:dec_fence_hitbox",
            {
                'sgs_farm:fence_north': block.permutation.getState("sgs_farm:fence_north"),
                'sgs_farm:fence_south': block.permutation.getState("sgs_farm:fence_south"),
                'sgs_farm:fence_east': block.permutation.getState("sgs_farm:fence_east"),
                'sgs_farm:fence_west': block.permutation.getState("sgs_farm:fence_west")
            }));

        highlightBlockTall(block);
        player.playSound("use.wood", { pitch: 1.0, volume: 1.0, });
        const mainhand = player.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand);
        if (player.getGameMode() == mc.GameMode.creative) return;
        mainhand.setItem(itemManager.reduceDurability(player, item, 2));

        return;
    }
    if (up.type.id == "sgs_farm:dec_fence_hitbox") {
        player.onScreenDisplay.setActionBar("§6[Fence]§f Hitbox 1.0");
        up.setPermutation(mc.BlockPermutation.resolve("minecraft:air"));

        highlightBlock(block);
        player.playSound("use.wood", { pitch: 1.0, volume: 1.0, });
        const mainhand = player.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand);
        if (player.getGameMode() == mc.GameMode.creative) return;
        mainhand.setItem(itemManager.reduceDurability(player, item, 2));

        return;
    }
}

function toggleHitboxGate(block, player, item) {

    const up = block.above();

    if (up.isAir) {
        player.onScreenDisplay.setActionBar("§6[Gate]§f Hitbox 1.5");
        up.setPermutation(mc.BlockPermutation.resolve("sgs_farm:dec_gate_hitbox",
            {
                'minecraft:cardinal_direction': block.permutation.getState('minecraft:cardinal_direction'),
                'sgs_farm:open': block.permutation.getState("sgs_farm:open"),
                'sgs_farm:open_south': block.permutation.getState("sgs_farm:open_south")
            }));

        highlightBlockTall(block);
        player.playSound("use.wood", { pitch: 1.0, volume: 1.0, });
        const mainhand = player.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand);
        if (player.getGameMode() == mc.GameMode.creative) return;
        mainhand.setItem(itemManager.reduceDurability(player, item, 2));

        return;
    }
    if (up.type.id == "sgs_farm:dec_gate_hitbox") {
        player.onScreenDisplay.setActionBar("§6[Gate]§f Hitbox 1.0");
        up.setPermutation(mc.BlockPermutation.resolve("minecraft:air"));

        highlightBlock(block);
        player.playSound("use.wood", { pitch: 1.0, volume: 1.0, });
        const mainhand = player.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand);
        if (player.getGameMode() == mc.GameMode.creative) return;
        mainhand.setItem(itemManager.reduceDurability(player, item, 2));

        return;
    }
}

//CONNECTION MODES
function checkConnectionMode(block) {
    let mode = mc.world.getDynamicProperty(blockToKey(block));
    if (mode == undefined) mode = -1;
    return mode;
}

function setConnectionMode(block, mode, player) {
    if (mode > 1) mode = 0;
    mc.world.setDynamicProperty(blockToKey(block), mode);
    player.playSound("use.wood", { pitch: 1.0, volume: 1.0, });
    switch (mode) {
        case 0:
            connectAll(block);
            player.onScreenDisplay.setActionBar("§6[Fence]§f Connect to all");
            break;
        case 1:
            connectSameType(block);
            player.onScreenDisplay.setActionBar("§6[Fence]§f Connect to same type");
            break;
        default:
            break;
    }
}

function connectSameType(block) {

    const north = block.north();
    const east = block.east();
    const south = block.south();
    const west = block.west();

    const northConnects = (north.hasTag("sgs_farm_fence"));
    const eastConnects = (east.hasTag("sgs_farm_fence"));
    const southConnects = (south.hasTag("sgs_farm_fence"));
    const westConnects = (west.hasTag("sgs_farm_fence"));

    if (northConnects && !north.hasTag("sgs_farm_fence")) updatePermutation(north, 'sgs_farm:fence_south', 0);
    if (eastConnects && !east.hasTag("sgs_farm_fence")) updatePermutation(east, 'sgs_farm:fence_west', 0);
    if (southConnects && !south.hasTag("sgs_farm_fence")) updatePermutation(south, 'sgs_farm:fence_north', 0);
    if (westConnects && !west.hasTag("sgs_farm_fence")) updatePermutation(west, 'sgs_farm:fence_east', 0);

    block.setPermutation(mc.BlockPermutation.resolve(block.permutation.type.id,
        {
            'sgs_farm:fence_north': northConnects ? 1 : 0,
            'sgs_farm:fence_south': southConnects ? 1 : 0,
            'sgs_farm:fence_east': eastConnects ? 1 : 0,
            'sgs_farm:fence_west': westConnects ? 1 : 0
        }));

    //update top hitbox
    const up = block.above();
    if (up.type.id == "sgs_farm:dec_fence_hitbox") {
        const newPermutation = mc.BlockPermutation.resolve(up.typeId, {
            'sgs_farm:fence_north': northConnects ? 1 : 0,
            'sgs_farm:fence_south': southConnects ? 1 : 0,
            'sgs_farm:fence_east': eastConnects ? 1 : 0,
            'sgs_farm:fence_west': westConnects ? 1 : 0
        });
        up.setPermutation(newPermutation);
    }

    if (up.hasTag("sgs_farm_fence_top")) {
        const newPermutation = mc.BlockPermutation.resolve(up.typeId, {
            'sgs_farm:fence_upper': 1,
            'sgs_farm:fence_north': northConnects ? 1 : 0,
            'sgs_farm:fence_south': southConnects ? 1 : 0,
            'sgs_farm:fence_east': eastConnects ? 1 : 0,
            'sgs_farm:fence_west': westConnects ? 1 : 0
        });
        up.setPermutation(newPermutation);
    }
}

function connectAll(block) {

    const north = block.north();
    const east = block.east();
    const south = block.south();
    const west = block.west();

    const northConnects = (!north.isLiquid && !north.isAir);
    const eastConnects = (!east.isLiquid && !east.isAir);
    const southConnects = (!south.isLiquid && !south.isAir);
    const westConnects = (!west.isLiquid && !west.isAir);

    if (northConnects && north.hasTag("sgs_farm_fence") && !north.hasTag("sgs_farm_gate")) updatePermutation(north, 'sgs_farm:fence_south', 1);
    if (eastConnects && east.hasTag("sgs_farm_fence") && !east.hasTag("sgs_farm_gate")) updatePermutation(east, 'sgs_farm:fence_west', 1);
    if (southConnects && south.hasTag("sgs_farm_fence") && !south.hasTag("sgs_farm_gate")) updatePermutation(south, 'sgs_farm:fence_north', 1);
    if (westConnects && west.hasTag("sgs_farm_fence") && !west.hasTag("sgs_farm_gate")) updatePermutation(west, 'sgs_farm:fence_east', 1);

    block.setPermutation(mc.BlockPermutation.resolve(block.permutation.type.id,
        {
            'sgs_farm:fence_north': northConnects ? 1 : 0,
            'sgs_farm:fence_south': southConnects ? 1 : 0,
            'sgs_farm:fence_east': eastConnects ? 1 : 0,
            'sgs_farm:fence_west': westConnects ? 1 : 0
        }));

    //update top hitbox
    const up = block.above();
    if (up.type.id == "sgs_farm:dec_fence_hitbox") {
        const newPermutation = mc.BlockPermutation.resolve(up.typeId, {
            'sgs_farm:fence_north': northConnects ? 1 : 0,
            'sgs_farm:fence_south': southConnects ? 1 : 0,
            'sgs_farm:fence_east': eastConnects ? 1 : 0,
            'sgs_farm:fence_west': westConnects ? 1 : 0
        });
        up.setPermutation(newPermutation);
    }

    if (up.hasTag("sgs_farm_fence_top")) {
        const newPermutation = mc.BlockPermutation.resolve(up.typeId, {
            'sgs_farm:fence_upper': 1,
            'sgs_farm:fence_north': northConnects ? 1 : 0,
            'sgs_farm:fence_south': southConnects ? 1 : 0,
            'sgs_farm:fence_east': eastConnects ? 1 : 0,
            'sgs_farm:fence_west': westConnects ? 1 : 0
        });
        up.setPermutation(newPermutation);
    }
}

function updatePermutation(block, state, number) {
    block.setPermutation(block.permutation.withState(state, number));

    if (block.above().hasTag("sgs_farm_fence_hitbox")) {
        const above = block.above();
        above.setPermutation(above.permutation.withState(state, number));
    }
}