import { world, MolangVariableMap } from "@minecraft/server"


export class FanComponent {
    constructor() {
        this.onTick = this.onTick.bind(this);
        this.onPlayerInteract = this.onPlayerInteract.bind(this);
        this.impulseVector = { x: 0, y: 0, z: 0 };
        this.tickCpt = 0
        this.REDSTONE_POWER_BLOCKS = [
            { id: "minecraft:redstone_wire", state: "redstone_signal" },
            { id: "minecraft:powered_comparator", state: "minecraft:cardinal_direction" },
            { id: "minecraft:powered_repeater", state: "minecraft:cardinal_direction" },
            { id: "minecraft:redstone_torch", state: "torch_facing_direction" },
            { id: "minecraft:observer", state: "minecraft:facing_direction" },
            { id: "minecraft:lever", state: "open_bit" },
            { id: "minecraft:lever", state: "open_bit" },
            { id: "_button", state: "button_pressed_bit" },
            { id: "_pressure_plate", state: "redstone_signal" },
            { id: "minecraft:redstone_block", state: null },
        ];
        this.EXLUDE_ENTITIES = [
            "minecraft:npc"
        ]
        this.PowerValue = 0
    }
    onPlayerInteract(e) {
        const block = e.block
        const player = e.player
        let selectedSlot = player.selectedSlotIndex;
        let handItem = player.getComponent("inventory").container.getItem(selectedSlot);
        if (handItem?.typeId == "pb_red:redstone_wrench") {
            const AllStates = [
                { state: "minecraft:cardinal_direction", values: ["north", "east", "south", "west"] },
                { state: "minecraft:facing_direction", values: ["north", "east", "south", "west", "up", "down"] }
            ]

            AllStates.some((stateObj) => {
                const currentState = block.permutation.getState(stateObj.state);

                if (currentState !== undefined && currentState !== null) {
                    const stateValues = stateObj.values;
                    const currentStateIndex = stateValues.indexOf(currentState);
                    const nextState = currentStateIndex >= stateValues.length - 1 ? stateValues[0] : stateValues[currentStateIndex + 1];

                    block.setPermutation(block.permutation.withState(stateObj.state, nextState));
                    block.dimension.runCommand(`playsound vr.stutterturn @a ${block.location.x} ${block.location.y} ${block.location.z}`)
                }
            });
            return;
        }

        if (block.permutation.getState('pb_red:powered') == false) return
        block.dimension.runCommand(`playsound vr.stutterturn @a ${block.location.x} ${block.location.y} ${block.location.z}`)
        if (block.permutation.getState('pb_red:inversed') == true) {
            block.setPermutation(block.permutation.withState('pb_red:inversed', false))
        } else {
            block.setPermutation(block.permutation.withState('pb_red:inversed', true))
        }
    }
    getFrontBlocks(direction, block) {
        let blocks = [];
        switch (direction) {
            case 'north':
                for (let i = 1; i <= 5; i++) {
                    blocks.push(block.north(i));
                }
                break;
            case 'south':
                for (let i = 1; i <= 5; i++) {
                    blocks.push(block.south(i));
                }
                break;
            case 'east':
                for (let i = 1; i <= 5; i++) {
                    blocks.push(block.east(i));
                }
                break;
            case 'west':
                for (let i = 1; i <= 5; i++) {
                    blocks.push(block.west(i));
                }
                break;
            case 'up':
                for (let i = 1; i <= 5; i++) {
                    blocks.push(block.above(i));
                }
                break;
            case 'down':
                for (let i = 1; i <= 5; i++) {
                    blocks.push(block.below(i));
                }
                break;
        }
        return blocks;
    }
    getImpulseDirection(direction) {
        switch (direction) {
            case 'north':
                return { x: 0, y: 0, z: -1 };
            case 'south':
                return { x: 0, y: 0, z: 1 };
            case 'east':
                return { x: 1, y: 0, z: 0 };
            case 'west':
                return { x: -1, y: 0, z: 0 };
            case 'up':
                return { x: 0, y: 1, z: 0 };
            case 'down':
                return { x: 0, y: -1, z: 0 };
        }
    }
    getOppositeDirection(direction) {
        switch (direction) {
            case 'north':
                return 'south';
            case 'south':
                return 'north';
            case 'east':
                return 'west';
            case 'west':
                return 'east';
            case 'up':
                return 'down';
            case 'down':
                return 'up';
        }
    }
    onTick(e) {
        const block = e.block;
        let direction = this.getOppositeDirection(block.permutation.getState('minecraft:facing_direction'));

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

        const adjacentBlocks = [north, east, south, west, above, below];
        const directionList = ["north", "east", "south", "west", "up", "down"];
        let hasRedstonePower = this.hasRedstonePower(adjacentBlocks, directionList)
        let redstonePowerValue = hasRedstonePower ? this.PowerValue : 0


        if (!block.permutation.matches("pb_red:fan")) return
        if (!hasRedstonePower) {
            block.setPermutation(block.permutation.withState('pb_red:powered', false));
            return
        }
        block.setPermutation(block.permutation.withState('pb_red:powered', true));

        this.tickCpt++
        if (this.tickCpt % 21 == 0) {
            block.dimension.runCommand(`playsound pb_red.fan_spinning_loop @a ${block.location.x} ${block.location.y} ${block.location.z} 0.2`)
        }

        const map = new MolangVariableMap()
        if (block.permutation.getState('pb_red:inversed')) {
            map.setSpeedAndDirection("variable.dir", redstonePowerValue, this.getImpulseDirection(this.getOppositeDirection(direction)))
            block.dimension.spawnParticle("pb_red:fan_suck_particle", { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 }, map)
        }
        else {
            map.setSpeedAndDirection("variable.dir", redstonePowerValue, this.getImpulseDirection(direction))
            block.dimension.spawnParticle("pb_red:fan_particle", { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 }, map)
        }

        let frontBlocks = this.getFrontBlocks(direction, block);

        const centerX = block.location.x + 0.5;
        const centerY = block.location.y + 0.5;
        const centerZ = block.location.z + 0.5;

        for (let i = 0; i < frontBlocks.length; i++) {
            if (frontBlocks[i].isSolid) {
                frontBlocks = frontBlocks.slice(0, i + 1);
                break;
            }
        }

        for (const frontBlock of frontBlocks) {
            const entities = block.dimension.getEntitiesAtBlockLocation(frontBlock.location);
            for (const entity of entities) {
                const dx = Math.abs(centerX - entity.location.x);
                const dy = Math.abs(centerY - entity.location.y);
                const dz = Math.abs(centerZ - entity.location.z);

                const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
                let force = redstonePowerValue == 0 ? 1 / distance : (1 / distance) * (redstonePowerValue / 15);
                let inversed = block.permutation.getState('pb_red:inversed') == true ? -1 : 1
                let impulseDirection = this.getImpulseDirection(direction)

                if (entity.typeId === 'minecraft:player' && !this.loadIgnoredEntities("Fan").includes('player') && !this.loadItemsOnlyMode("Fan")) {
                    entity.applyKnockback(impulseDirection.x, impulseDirection.z, force * 2 * inversed, impulseDirection.y ? force * 2 * impulseDirection.y * inversed : 0);
                    // autre possibilité en dessous mais depend de la vitesse du joueur a l'entré
                    // entity.applyKnockback(impulseDirection.x + (entity.getVelocity().x * entity.getVelocity().x * entity.getVelocity().x), impulseDirection.z + (entity.getVelocity().z * entity.getVelocity().z * entity.getVelocity().z), force * 2, impulseDirection.y ? force * 2 * impulseDirection.y : 0);
                } else {
                    this.impulseVector.x = (dx / distance) * force * impulseDirection.x * inversed;
                    this.impulseVector.y = (dy / distance) * force * impulseDirection.y * inversed;
                    this.impulseVector.z = (dz / distance) * force * impulseDirection.z * inversed;

                    if (
                        (!this.loadIgnoredEntities("Conveyor").includes(entity.typeId.replace("minecraft:", "").replace("_v2", "")) && !this.loadItemsOnlyMode("Fan"))
                        || (entity.typeId == "minecraft:item" && this.loadItemsOnlyMode("Fan"))
                    ) {
                        entity.applyImpulse(this.impulseVector);
                    }
                }
            }
        }
    }

    hasRedstonePower(adjacentBlocks, directionList) {

        return adjacentBlocks.some((adjacentBlock, index) => {
            if (!adjacentBlock) return false;

            const redstoneBlock = this.REDSTONE_POWER_BLOCKS.find(({ id }) => adjacentBlock.typeId.includes(id));
            if (!redstoneBlock) return false;
            this.PowerValue = 15
            const { id, state } = redstoneBlock;
            if (id === "minecraft:redstone_block") return true;

            if (id === "minecraft:redstone_wire") {
                let redstonePowerState = adjacentBlock.permutation.getState(state);
                this.PowerValue = redstonePowerState
                return redstonePowerState > 0;
            }

            if (id === "minecraft:powered_comparator" || id === "minecraft:powered_repeater") {
                return adjacentBlock.permutation.getState(state) === directionList[index];
            }

            if (id === "minecraft:redstone_torch") {
                return adjacentBlock.permutation.getState(state) !== this.getOppositeDirection(directionList[index]) && index !== 4;
            }

            if (id === "minecraft:observer") {
                return adjacentBlock.permutation.getState(state) == directionList[index] && adjacentBlock.permutation.getState("powered_bit") == true;
            }

            if (id === "minecraft:lever") {
                return adjacentBlock.permutation.getState(state) == true;
            }

            if (id === "_button") {
                return adjacentBlock.permutation.getState(state) == true;
            }

            if (id === "_pressure_plate") {
                return adjacentBlock.permutation.getState(state) > 0;
            }

            return false;
        });
    }

    loadIgnoredEntities(block) {
        const data = world.getDynamicProperty(`pb_red:IgnoredEntities:${block}`);
        if (data) {
            return JSON.parse(data);
        }
        return [];
    }

    loadItemsOnlyMode(block) {
        const data = world.getDynamicProperty(`pb_red:ItemsOnlyMode:${block}`);
        return data ? JSON.parse(data) : false;
    }
}


