import { world, system } from "@minecraft/server";
import { fo } from "../utilities/fo_constants";






export function getDistance3D(pos1, pos2) {
    return Math.sqrt(
        (pos1.x - pos2.x) ** 2 +
        (pos1.y - pos2.y) ** 2 +
        (pos1.z - pos2.z) ** 2
    );
}


export function getDistance2D(pos1, pos2) {
    return Math.sqrt(
        (pos1.x - pos2.x) ** 2 +
        (pos1.z - pos2.z) ** 2
    );
}

export function isDate(month, days) {
    const now = new Date();
    if (now.getMonth() !== month) return false;

    const today = now.getDate();
    return days.includes(today);

    
}





export function doorOpenCloses(player) {
    
    const
        DOOR_LIST_PROPERTY = "door_locations",

        doorLocations = JSON.parse(world.getDynamicProperty(DOOR_LIST_PROPERTY) || "[]"),
        playerDim = player.dimension.id;

    if (!doorLocations || doorLocations.length === 0) return;

    const nearbyDoors = doorLocations.filter(loc => {
        if (loc.dimensionId !== playerDim) return false;
        const distance = getDistance(player.location, loc);
        return distance >= 6 && distance <= 32;
    });

    if (nearbyDoors.length === 0) return;


    
    const woodenDoors = fo.doorIds;

    
    const copperDoor = fo.copperDoorIds;

    
    const doorPos = nearbyDoors[Math.floor(Math.random() * nearbyDoors.length)];
    const dimension = world.getDimension(doorPos.dimensionId);
    const block = dimension.getBlock(doorPos);
    if (!block) return;

    if (!woodenDoors.includes(block.typeId)) {
        removeDoorFromList(doorPos, doorLocations);
        return
    };

    const isUpper = block.permutation.getState("upper_block_bit");
    if (isUpper) return;

    const isOpen = block.permutation.getState("open_bit");



    const newState = block.permutation.withState("open_bit", !isOpen);
    block.setPermutation(newState);

    
    const sound = isOpen ? "random.door_close" : "random.door_open";
    const copperSound = isOpen ? "close_door.copper" : "open_door.copper";
    dimension.playSound(
        copperDoor.includes(block.typeId) ? copperSound : sound,
        block.location,
        { volume: 2 }
    );


    

    
    function getDistance(pos1, pos2) {
        if (!pos1 || !pos2) {
            return Infinity; 
        }
        return Math.sqrt(
            Math.pow(pos1.x - pos2.x, 2) +
            Math.pow(pos1.y - pos2.y, 2) +
            Math.pow(pos1.z - pos2.z, 2)
        );
    };

    
    function removeDoorFromList(door, doorLocations) {
        const updatedLocations = doorLocations.filter(loc =>
            !(loc.x === door.x &&
                loc.y === door.y &&
                loc.z === door.z &&
                loc.dimensionId === door.dimensionId)
        );
        world.setDynamicProperty(DOOR_LIST_PROPERTY, JSON.stringify(updatedLocations));
        

    };

}





export function playRandomNoises(player) {
    const overworld = fo.overworld;
    if (player.dimension !== overworld) return;

    
    const sounds = [
        { name: "mob.zombie.say", maxDistance: 2, weight: 1, type: "regular" },
        { name: "mob.skeleton.step", maxDistance: 2, weight: 1, type: "regular" },
        { name: "ambient.cave", maxDistance: 2, weight: 8, type: "regular" },
        
        { name: "game.player.hurt", maxDistance: 2, weight: 1, type: "regular" },
        { name: "damage.fallbig", maxDistance: 2, weight: 1, type: "regular" },
        
        { name: "random.levelup", maxDistance: 2, weight: 1, type: "regular" },
        
        
        
        
        { name: "armor.equip_iron", maxDistance: 2, weight: 1, type: "regular" },
        { name: "random.break", maxDistance: 2, weight: 1, type: "regular" },
        { name: "random.pop", maxDistance: 2, weight: 1, type: "regular" },


        
        { name: "block_breaking_chain", maxDistance: 2, weight: 1, type: "function", action: playBlockBreakingChain },
        { name: "block_placing_chain", maxDistance: 2, weight: 1, type: "function", action: playBlockPlacingChain },
        { name: "water_placing", maxDistance: 2, weight: 1, type: "function", action: playWaterPlacing },
        { name: "player_eating", maxDistance: 2, weight: 1, type: "function", action: playPlayerEating },
        { name: "player_drinking", maxDistance: 2, weight: 1, type: "function", action: playPlayerDrinking }
    ];

    
    const validBlocks = fo.validMinedBlocks;

    const ValidBlocksArray = fo.ValidMinedBlocksArray;

    
    const validBlocksMap = new Map();
    ValidBlocksArray.forEach(block => {
        validBlocksMap.set(block.id, block);
    });

    
    const
        BREAKINGSOUNDINTERVAL = 6, 
        BREAKINTERVAL = BREAKINGSOUNDINTERVAL * 4,
        PLACEINTERVAL = 4,
        EATSOUNDINTERVAL = 4;


    

    function playBlockBreakingChain(overworld, soundLocation) {
        try {
            const block = overworld.getBlock(soundLocation);
            if (block && validBlocks.includes(block.typeId)) {
                blockBreakingAction(overworld, block, soundLocation);
                return true;
            }
        } catch (e) {
            
        }
        return false;
    }

    function playBlockPlacingChain(overworld, soundLocation) {
        try {
            const block = overworld.getBlock(soundLocation);
            if (block && validBlocks.includes(block.typeId)) {
                blockPlacingAction(overworld, block, soundLocation);
                return true;
            }
        } catch (e) {
            
        }
        return false;
    }

    function playWaterPlacing(overworld, soundLocation) {
        waterPlacingAction(overworld, soundLocation);
        return true;
    }

    function playPlayerEating(overworld, soundLocation) {
        playerEating(overworld, soundLocation);
        return true;
    }

    function playPlayerDrinking(overworld, soundLocation) {
        playerdrinking(overworld, soundLocation);
        return true;
    }


    

    function blockBreakingAction(overworld, block, blockLoc) {
        const data = validBlocksMap.get(block.typeId);
        if (!data) return;
        const breakingSoundInterval = system.runInterval(() => {
            overworld.playSound(data.beingBrokenSound, blockLoc, {
                volume: 2,
            });
        }, BREAKINGSOUNDINTERVAL)

        system.runTimeout(() => {
            overworld.playSound(data.brokenSound, blockLoc, {
                volume: 2,
            });
            system.clearRun(breakingSoundInterval)
            if (Math.random() > 0.8) {
                if (Math.random() < 0.1) overworld.playSound("random.break", blockLoc, { pitch: 1, volume: 2 });
                return;
            };
            system.runTimeout(() => {
                const nearbyPlayers = overworld.getPlayers({
                    location: blockLoc,
                    maxDistance: 8
                });
                if (nearbyPlayers.length !== 0) {
                    if (Math.random() < 0.2) playerdrinking(overworld, blockLoc);
                    return
                };
                const randomDirection = [
                    { x: blockLoc.x + 1, y: blockLoc.y, z: blockLoc.z },
                    { x: blockLoc.x - 1, y: blockLoc.y, z: blockLoc.z },
                    { x: blockLoc.x, y: blockLoc.y + 1, z: blockLoc.z },
                    { x: blockLoc.x, y: blockLoc.y - 1, z: blockLoc.z },
                    { x: blockLoc.x, y: blockLoc.y, z: blockLoc.z + 1 },
                    { x: blockLoc.x, y: blockLoc.y, z: blockLoc.z - 1 },
                ]
                try {
                    const
                        roll = Math.floor(Math.random() * randomDirection.length),
                        newBlock = overworld.getBlock(randomDirection[roll]),
                        newBlockLoc = newBlock.location;
                    if (Math.random() < 0.5) blockBreakingAction(overworld, newBlock, newBlockLoc);
                    else blockPlacingAction(overworld, newBlock, newBlockLoc);
                } catch (e) { }
            }, Math.floor(Math.random() * 7) + 6);
        }, BREAKINTERVAL);

    };

    function blockPlacingAction(overworld, block, blockLoc) {
        const data = validBlocksMap.get(block.typeId);
        if (!data) return;

        system.runTimeout(() => {
            overworld.playSound(data.beingBrokenSound, blockLoc, {
                volume: 2,
            });

            if (Math.random() > 0.8) return;
            system.runTimeout(() => {
                const nearbyPlayers = overworld.getPlayers({
                    location: blockLoc,
                    maxDistance: 8
                });
                if (nearbyPlayers.length !== 0) {
                    if (Math.random() < 0.2) playerdrinking(overworld, blockLoc);
                    return
                };
                const randomDirection = [
                    { x: blockLoc.x + 1, y: blockLoc.y, z: blockLoc.z },
                    { x: blockLoc.x - 1, y: blockLoc.y, z: blockLoc.z },
                    { x: blockLoc.x, y: blockLoc.y + 1, z: blockLoc.z },
                    { x: blockLoc.x, y: blockLoc.y - 1, z: blockLoc.z },
                    { x: blockLoc.x, y: blockLoc.y, z: blockLoc.z + 1 },
                    { x: blockLoc.x, y: blockLoc.y, z: blockLoc.z - 1 },
                ]
                try {
                    const
                        roll = Math.floor(Math.random() * randomDirection.length),
                        newBlock = overworld.getBlock(randomDirection[roll]),
                        newBlockLoc = newBlock.location;
                    if (Math.random() < 0.5) blockBreakingAction(overworld, newBlock, newBlockLoc);
                    else blockPlacingAction(overworld, newBlock, newBlockLoc);
                } catch (e) { }
            }, Math.floor(Math.random() * 7) + 6);
        }, PLACEINTERVAL)

    };

    function waterPlacingAction(overworld, blockLoc) {
        system.runTimeout(() => {
            overworld.playSound("bucket.empty_water", blockLoc, {
                volume: 2,
            });
        }, PLACEINTERVAL)

    };

    function playerEating(overworld, blockLoc) {
        const eatingSoundInterval = system.runInterval(() => {
            overworld.playSound("random.eat", blockLoc, {
                volume: 2,
                pitch: Math.random() < 0.5 ? 0.8 : 1.12,
            });
        }, EATSOUNDINTERVAL)

        system.runTimeout(() => {
            overworld.playSound("random.burp", blockLoc, {
                volume: 2,
                pitch: Math.random() < 0.5 ? 0.9 : 1,
            });
            system.clearRun(eatingSoundInterval)
        }, EATSOUNDINTERVAL * Math.floor(Math.random() * 5 + 6));
    };

    function playerdrinking(overworld, blockLoc) {
        const drinkingSoundInterval = system.runInterval(() => {
            overworld.playSound("random.drink", blockLoc, {
                volume: 2,
                pitch: Math.random() < 0.5 ? 0.9 : 1.1,
            });
        }, EATSOUNDINTERVAL)

        system.runTimeout(() => {
            overworld.playSound("random.burp", blockLoc, {
                volume: 2,
                pitch: Math.random() < 0.5 ? 0.9 : 1,
            });
            system.clearRun(drinkingSoundInterval)
        }, EATSOUNDINTERVAL * Math.floor(Math.random() * 5 + 6));
    };


    

    
    function getTotalWeight(soundArray) {
        return soundArray.reduce((total, sound) => total + sound.weight, 0);
    }

    
    function selectSound(soundArray, targetLocation, playerLocation) {
        
        const filteredSounds = soundArray.filter(sound => {
            if (!sound.maxDistance) return true; 

            const distance = getDistance3D(targetLocation, playerLocation);
            const soundRange = sound.maxDistance * 16; 

            return distance < soundRange;
        });

        
        if (filteredSounds.length === 0) {
            return null;
        }

        const totalWeight = getTotalWeight(filteredSounds);
        let randomValue = Math.random() * totalWeight;

        for (const sound of filteredSounds) {
            if (randomValue < sound.weight) {
                return sound;
            }
            randomValue -= sound.weight;
        }
        return filteredSounds[0]; 
    }

    
    function getPositionAround(center, minDistance, maxDistance, dimension) {
        const angle = Math.random() * Math.PI * 2;
        const distanceXZ = minDistance + Math.random() * (maxDistance - minDistance);
        const distanceY = (Math.random() - 0.5) * (maxDistance - minDistance); 

        return {
            x: center.x + Math.cos(angle) * distanceXZ,
            y: Math.max(Math.min(center.y + distanceY, dimension.heightRange.max), dimension.heightRange.min), 
            z: center.z + Math.sin(angle) * distanceXZ,
        };
    }

    
    function isLocationSafe(dimension, location, player) {
        
        const block = dimension.getBlock(location);
        if (!block || block.isAir || block.isLiquid || !validBlocks.includes(block.typeId)) {
            return false;
        }

        
        const distance = getDistance3D(location, player.location);
        if (distance < 15) {
            return false;
        }

        return true;
    }


    
    

    
    let soundLocation;
    let attempts = 0;
    do {
        soundLocation = getPositionAround(player.location, 15, 29, player.dimension); 
        attempts++;
    } while (!isLocationSafe(player.dimension, soundLocation, player) && attempts < 60);

    if (!soundLocation || !isLocationSafe(player.dimension, soundLocation, player)) {
        
        return; 
    }

    
    const selectedSound = selectSound(sounds, soundLocation, player.location);
    if (!selectedSound) return;
    
    if (selectedSound.type === "regular") {
        
        overworld.playSound(selectedSound.name, soundLocation, { pitch: 1, volume: selectedSound.maxDistance });
        
    } else if (selectedSound.type === "function" && selectedSound.action) {
        
        const success = selectedSound.action(overworld, soundLocation);
        if (success) {
            
        } else {
            
        }
    }
}