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


export function initNoises() {

    
    const chanceSound = 1 / 600; 
    const SOUND_INTERVAL = 39; 
    const chanceCaveNoise = 1 / 400; 
    const CAVE_NOISE_INTERVAL = 61; 

    let probabilityBooster = 0; 

    
    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 caveNoises = [
        { name: "fo_cave", weight: 18 },
        { name: "corruption_ambience", weight: 1 }
    ];

    
    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 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 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 = getDistance(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, players) {
        
        const block = dimension.getBlock(location);
        if (!block || block.isAir || block.isLiquid || !validBlocks.includes(block.typeId)) {
            return false;
        }

        
        for (const player of players) {
            const distance = getDistance(location, player.location);
            if (distance < 15) {
                return false;
            }
        }

        return true;
    }

    
    function playRandomNoises() {
        const forebodingScore = fo.forebodingScore;
        if (forebodingScore < fo.scoreChapter3) return;

        if (forebodingScore >= fo.scoreChapter5) {
            probabilityBooster = 3
        } else { probabilityBooster = 0 }

        if (Math.random() > (chanceSound * (fo.multiplayerProbabilityModifier + probabilityBooster))) return;

        const overworld = fo.overworld;
        const players = overworld.getPlayers(); 
        if (players.length === 0) return;

        const player = players[Math.floor(Math.random() * players.length)];

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

        if (!soundLocation || !isLocationSafe(player.dimension, soundLocation, players)) {
            
            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 {
                
            }
        }
    }

    
    function playCaveNoises() {
        const forebodingScore = fo.forebodingScore;
        if (forebodingScore < fo.scoreChapter3) return;

        if (forebodingScore >= fo.scoreChapter5) {
            probabilityBooster = 3
        } else { probabilityBooster = 0 }

        if (Math.random() > (chanceCaveNoise * (fo.multiplayerProbabilityModifier + probabilityBooster))) return;

        
        

        const overworld = fo.overworld;
        const players = overworld.getPlayers(); 
        if (players.length === 0) return;

        
        const playersBelowY50 = players.filter(player => player.location.y <= 50);

        const player = playersBelowY50[Math.floor(Math.random() * players.length)];
        if (!player) return;
        if (player.location.y > 50) return;

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

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

        
        const sound = Math.random() < 0.95 ? caveNoises[0].name : caveNoises[1].name
        overworld.playSound(sound, soundLocation, { pitch: 1, volume: 4 });
        
    }

    
    system.runInterval(() => {
        playRandomNoises();
    }, SOUND_INTERVAL);

    
    system.runInterval(() => {
        playCaveNoises();
    }, CAVE_NOISE_INTERVAL);


}

