import { world, system } from "@minecraft/server"
import { Vector } from './vector.js';
import { ChannelKey } from './channel_key.js';


export class EntityTeleporterComponent {
    constructor() {
        this.onStepOn = this.onStepOn.bind(this);
        this.onPlayerInteract = this.onPlayerInteract.bind(this);
        this.beforeOnPlayerPlace = this.beforeOnPlayerPlace.bind(this);

        this.COLOR_DYE_LIST = [
            "minecraft:black_dye",
            "minecraft:blue_dye",
            "minecraft:brown_dye",
            "minecraft:cyan_dye",
            "minecraft:gray_dye",
            "minecraft:green_dye",
            "minecraft:light_blue_dye",
            "minecraft:light_gray_dye",
            "minecraft:lime_dye",
            "minecraft:magenta_dye",
            "minecraft:orange_dye",
            "minecraft:pink_dye",
            "minecraft:purple_dye",
            "minecraft:red_dye",
            "minecraft:white_dye",
            "minecraft:yellow_dye"
        ];
        this.Color_List = [
            "§0black",
            "§1blue",
            "brown",
            "§3cyan",
            "§8gray",
            "§2green",
            "§blight blue",
            "§7light gray",
            "§alime",
            "§5magenta",
            "§6orange",
            "§dpink",
            "§5purple",
            "§4red",
            "§fwhite",
            "§eyellow"
        ];
    }

    beforeOnPlayerPlace(e) {
        const block = e.block;
        const player = e.player
        const permutationToPlace = e.permutationToPlace;
        const currentColorChannel = block.permutation.getState('pb_red:color_channel');
        //   console.warn("placed")
        try {
            if (block) {
                for (let i = 0; i <= 15; i++) {
                    const wasLoc = this.removeEntityTeleporterData(block, i);

                    if (wasLoc) {
                        e.cancel = true
                        system.runTimeout(() => {
                            player.sendMessage(`§2The bugged Entity Teleporter Location has been removed from the §l${this.Color_List[i]}§r§2 color channel.`)
                        }, 1)
                    }
                }
            }
        } catch (e) {
            //console.warn(e)
        }

    }

    getEntityTeleporterData() {
        return JSON.parse(world.getDynamicProperty("pb_red:entity_teleporter_data") || "[]");
    }

    getTeleporterSettings() {
        const info = world.getDynamicProperty(`pb_red:entity_teleporter_settings`) || null;
        if (info) {
            return JSON.parse(info)
        } else {
            return { enable: true, crossDim: true, distLimited: false, range: 10000 };
        }
    }

    setEntityTeleporterData(data) {
        world.setDynamicProperty("pb_red:entity_teleporter_data", JSON.stringify(data));
    }

    updateEntityTeleporterData(block, colorChannel) {
        const locationStr = `${block.location.x},${block.location.y},${block.location.z},${block.dimension.id}`;

        let data = this.getEntityTeleporterData();
        let channelData = data.find(d => d.channel === colorChannel);

        if (!channelData) {
            channelData = { channel: colorChannel, teleporters: [] };
            data.push(channelData);
        }

        if (!channelData.teleporters.includes(locationStr)) {
            channelData.teleporters.push(locationStr);
        }

        this.setEntityTeleporterData(data);
    }

    removeEntityTeleporterData(block, colorChannel) {
        let wasLoc = false
        const locationStr = `${block.location.x},${block.location.y},${block.location.z},${block.dimension.id}`;
        //  console.warn(block.dimension.id)
        let data = this.getEntityTeleporterData();
        let channelData = data.find(d => d.channel === colorChannel);

        if (channelData) {

            const newchannelDataTeleporters = channelData.teleporters.filter(loc => loc !== locationStr);

            if (channelData.teleporters.length !== newchannelDataTeleporters.length) wasLoc = true

            channelData.teleporters = newchannelDataTeleporters
            if (channelData.teleporters.length === 0) {
                data = data.filter(d => d.channel !== colorChannel);
            }

        }

        this.setEntityTeleporterData(data);
        return wasLoc
    }

    onPlayerInteract(e) {
        const block = e.block;
        const player = e.player;
        let selectedSlot = player.selectedSlotIndex;
        let handItem = player.getComponent("inventory").container.getItem(selectedSlot);
        block.dimension.spawnParticle("pb_red:portal_idle", { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 })
        const currentColorChannel = block.permutation.getState('pb_red:color_channel');

        if (handItem?.typeId == "pb_red:redstone_wrench") {
            //   if (block.permutation.getState('pb_red:powered') == true) {
            block.dimension.runCommand(`playsound random.click @a ${block.location.x} ${block.location.y} ${block.location.z}`)

            const channelKey = new ChannelKey(block, null);
            channelKey.openUI(player)

            return;
            // }
        }

        if (currentColorChannel !== undefined) {
            this.removeEntityTeleporterData(block, currentColorChannel);
        }

        if (this.COLOR_DYE_LIST.includes(handItem?.typeId)) {
            block.setPermutation(block.permutation.withState('pb_red:powered', true));
            let colorChannel = this.COLOR_DYE_LIST.indexOf(handItem.typeId);
            block.setPermutation(block.permutation.withState('pb_red:color_channel', colorChannel));
            player.runCommand(`clear @s ${handItem.typeId} 0 1`);
            block.dimension.runCommand(`playsound block.end_portal_frame.fill @a ${block.location.x} ${block.location.y} ${block.location.z}`)
            // console.warn("channel set to : " + colorChannel);
            this.updateEntityTeleporterData(block, colorChannel);
        }
    }

    validateTeleporterLocations(colorChannel, block, entity) {
        let data = this.getEntityTeleporterData();
        let channelData = data.find(d => d.channel === colorChannel);

        if (channelData) {
            channelData.teleporters = channelData.teleporters.filter(locStr => {
                const [targetX, targetY, targetZ, targetDimension] = locStr.split(',');
                const targetXNum = parseFloat(targetX);
                const targetYNum = parseFloat(targetY);
                const targetZNum = parseFloat(targetZ);
                const targetDimensionInstance = world.getDimension(targetDimension);
                const destinationBlock = world.getDimension(targetDimension).getBlock({ x: targetXNum, y: targetYNum, z: targetZNum });
                return destinationBlock.typeId === block.typeId && destinationBlock.permutation.getState('pb_red:color_channel') === block.permutation.getState('pb_red:color_channel');

            });

            this.setEntityTeleporterData(data);
        }
    }

    onStepOn(e) {
        const block = e.block;
        const colorChannel = block.permutation.getState('pb_red:color_channel');
        this.updateEntityTeleporterData(block, colorChannel);
        const settings = this.getTeleporterSettings();
        // this.validateTeleporterLocations(colorChannel, block);

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

        const entities = block.dimension.getEntities({
            location: block.location,
            maxDistance: 1.5,
            excludeTypes: ["minecraft:item"]
        });
        block.dimension.spawnParticle("pb_red:portal_idle", { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 })
        for (const entity of entities) {
            if (this.loadIgnoredEntities("Entity Teleporter").includes(entity.typeId.replace("minecraft:", "").replace("_v2", ""))) return
            if ((entity.hasTag("pb_red:EntityTeleporterCD") || block.permutation.getState('pb_red:powered') == false)) {
                block.dimension.spawnParticle("pb_red:portal_port", { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 })
                system.runTimeout(() => {
                    entity?.removeTag("pb_red:EntityTeleporterCD");
                }, 10)
                return;
            }
            let data = this.getEntityTeleporterData();
            let channelData = data.find(d => (d.channel === colorChannel));

            if (channelData && channelData.teleporters.length > 1) {

                const currentLocationStr = `${block.location.x},${block.location.y},${block.location.z},${block.dimension.id}`;
                const otherTeleporters = channelData.teleporters.filter(loc => loc !== currentLocationStr);

                // Verify channel keys for all potential teleporters
                const validTeleporters = otherTeleporters.filter(targetLocationStr => {
                    const [targetX, targetY, targetZ, targetDimension] = targetLocationStr.split(',');
                    const targetXNum = parseFloat(targetX);
                    const targetYNum = parseFloat(targetY);
                    const targetZNum = parseFloat(targetZ);
                    const targetLoc = new Vector(targetXNum, targetYNum, targetZNum);

                    const targetBlock = ChannelKey.constructBlock(targetLoc, targetDimension);
                    const channelKey = new ChannelKey(block, targetBlock);

                    return channelKey.channelConfirmed();
                });

                // Select a random valid teleporter
                if (validTeleporters.length === 0) {
                    //   console.warn("No valid teleporters available.");
                    return; // Exit if no valid teleporters exist
                }

                const targetLocationStr = validTeleporters[Math.floor(Math.random() * validTeleporters.length)];
                const [targetX, targetY, targetZ, targetDimension] = targetLocationStr.split(',');
                const targetXNum = parseFloat(targetX);
                const targetYNum = parseFloat(targetY);
                const targetZNum = parseFloat(targetZ);
                const targetLoc = new Vector(targetXNum, targetYNum, targetZNum);
                const targetDimensionInstance = world.getDimension(targetDimension);





                if (!settings.enable) {
                    if (entity.typeId == "minecraft:player") entity.sendMessage("§cThe Entity Teleporter has been disabled in the customization section.")
                    return
                }
                if (block.dimension.id !== targetDimension && !settings.crossDim) {
                    if (entity.typeId == "minecraft:player") entity.sendMessage("§cThe Entity Teleporter Settings don't allow to do cross dimension teleportation.")
                    return
                }
                if (Vector.distanceBetween(new Vector(targetXNum, targetYNum, targetZNum), entity.location) > settings.range && settings.distLimited) {
                    if (entity.typeId == "minecraft:player") entity.sendMessage(`§cThe Entity Teleporter Settings limit the teleportation range to §4${settings.range}§c.`)
                    return
                }

                block.dimension.spawnParticle("pb_red:portal_port", { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 })
                entity.addTag("pb_red:EntityTeleporterCD");

                entity.teleport({ x: targetXNum + 0.5, y: targetYNum + 0.5, z: targetZNum + 0.5, }, { dimension: targetDimensionInstance });
                block.dimension.runCommand(`playsound mob.shulker.teleport @a ${block.location.x} ${block.location.y} ${block.location.z}`)
                try {
                    system.runTimeout(() => {
                        entity.runCommand(`playsound mob.shulker.teleport @a ~ ~ ~`)
                    }, 5)
                } catch { }
            }
        }
    }
    loadIgnoredEntities(block) {
        const data = world.getDynamicProperty(`pb_red:IgnoredEntities:${block}`);
        if (data) {
            return JSON.parse(data);
        }
        return [];
    }
}
