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











export function initVoidVillage() {
    
    const
        villageCenter = { x: 400512, y: 2, z: 400528 }, 
        blinkChance = 1 / 10, 
        ambientSoundChance = 1 / 60, 
        bellSoundChance = 1 / 66, 
        theEnd = fo.theEnd,
        INNER_RADIUS = 420,
        OUTER_RADIUS = 440,
        BORDER_RADIUS = 520;


    
    const
        ambientSoundRadius = 100, 
        maxAttempts = 20; 

    
    
    function getCurrentVisitors() {
        const visitors = world.getDynamicProperty("void_village_visitors");
        return new Set(visitors ? JSON.parse(visitors) : []);
    }

    function saveCurrentVisitors(visitorSet) {
        world.setDynamicProperty("void_village_visitors", JSON.stringify([...visitorSet]));
    }

    function addVisitor(player) {
        const visitors = getCurrentVisitors();
        visitors.add(player.id);
        saveCurrentVisitors(visitors);
    }

    function removeVisitor(player) {
        const visitors = getCurrentVisitors();
        visitors.delete(player.id);
        saveCurrentVisitors(visitors);
    }

    
    function getPositionAround(center, radius) {
        const angle = Math.random() * Math.PI * 2;
        const distance = radius;
        return {
            x: center.x + Math.cos(angle) * distance,
            y: center.y,
            z: center.z + Math.sin(angle) * distance,
        };
    }

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

    function playVoidAmbience(visitors) {
        const targetPlayer = visitors[0];
        let validLocation = null;
        let attempts = maxAttempts;

        while (attempts-- > 0) {
            const soundPos = getPositionAround(targetPlayer.location, ambientSoundRadius);
            let locationIsSafe = true;

            
            for (const visitor of visitors) {
                const distance = getDistance(visitor.location, soundPos)

                

                if (distance < ambientSoundRadius) {
                    locationIsSafe = false;
                    break;
                }
            }

            if (locationIsSafe) {
                validLocation = soundPos;
                break;
            }
        }

        if (validLocation) {
            const soundChoice = Math.random() < 0.7 ?
                { id: "horn.call.7", pitch: 0.9 } :
                { id: "fo_mob.ghast.scream", pitch: 0.3 };

            theEnd.playSound(soundChoice.id, validLocation, {
                pitch: soundChoice.pitch,
                volume: 10,
                minimumDelay: 0
            });
            
        }
    }

    
    function playBellSound(visitors) {

        const bellPos = { x: 400523, y: 3, z: 400526 };

        
        for (const visitor of visitors) {
            const distance = getDistance(visitor.location, bellPos)

            

            if (distance > ambientSoundRadius) { 

                const adjustedVolume = Math.max(Math.floor(distance / 16) + 1, 1);

                theEnd.playSound("fo_block.bell.hit", bellPos, {
                    pitch: Math.random() * 0.5 + 0.35,
                    volume: adjustedVolume,
                    minimumDelay: 0
                });
                system.runTimeout(() => { 
                    theEnd.playSound("fo_block.bell.hit", bellPos, {
                        pitch: Math.random() * 0.5 + 0.35,
                        volume: adjustedVolume,
                        minimumDelay: 0
                    });
                }, 57)

                break;
            }
        }

    }

    
    system.runInterval(() => {

        const newVisitors = theEnd.getPlayers({
            location: villageCenter,
            maxDistance: BORDER_RADIUS
        });

        const currentVisitorIds = getCurrentVisitors();

        
        for (const visitorId of currentVisitorIds) {
            const player = [...world.getPlayers()].find(p => p.id === visitorId);
            if (!player || !newVisitors.some(p => p.id === visitorId)) {
                
                if (player) {
                    player.setGameMode(GameMode.Survival);
                    player.stopMusic();
                    player.runCommand(`fog @s remove Fog`);
                    player.setDynamicProperty("hasBeenTeleported", false);
                }
                removeVisitor(player || { id: visitorId });
            }
        }

        
        for (const player of newVisitors) {
            if (!currentVisitorIds.has(player.id)) {
                
                player.setGameMode(GameMode.Adventure);
                player.playMusic("phurpa", {
                    fade: 10,
                    loop: true,
                    volume: 0.08,
                });
                player.runCommand(`fog @s push foreboding:fog08ub Fog`);
                addVisitor(player);
            }
        }

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

        
        for (const player of newVisitors) {
            if (Math.random() <= blinkChance) {
                player.camera.fade({
                    fadeTime: {
                        fadeInTime: 0.5,
                        holdTime: 0.5,
                        fadeOutTime: 0.5,
                    },
                    fadeColor: {
                        red: 0,
                        green: 0,
                        blue: 0,
                    },
                })
                
            }
        }

        
        
        system.runTimeout(() => {

            if (Math.random() <= ambientSoundChance) { 
                
                playVoidAmbience(newVisitors);
            }

        }, 51);

        
        
        system.runTimeout(() => {

            if (Math.random() <= bellSoundChance) { 
                
                playBellSound(newVisitors);
            }

        }, 91);

    }, 184) 


    
    system.runInterval(() => {
        let hasVisitors = getCurrentVisitors().size > 0;

        
        if (!hasVisitors) {
            const netherVisitors = fo.nether.getPlayers({ location: { x: 100272, y: 64, z: 100256 }, maxDistance: 220 })
            hasVisitors = netherVisitors.length > 0;

        };

        
        if (world.gameRules.respawnBlocksExplode != !hasVisitors) {

            world.gameRules.respawnBlocksExplode = !hasVisitors;
        }
        
        if (hasVisitors && world.gameRules.showCoordinates) {
            world.gameRules.showCoordinates = false;
        }

        
        
        const visitors = theEnd.getPlayers({
            location: villageCenter,
            maxDistance: BORDER_RADIUS
        });
        if (visitors.length === 0) return;

        for (const player of visitors) {
            const gameMode = player.getGameMode();
            if (gameMode !== "Adventure") {
                player.setGameMode(GameMode.Adventure);
            }
        }

    }, 6);


    
    function getOppositePosition(playerPos) {
        
        const dx = playerPos.x - villageCenter.x;
        const dz = playerPos.z - villageCenter.z;

        
        const angle = Math.atan2(dz, dx);

        
        const oppositeAngle = angle + Math.PI;

        
        const newX = villageCenter.x + Math.cos(oppositeAngle) * INNER_RADIUS;
        const newZ = villageCenter.z + Math.sin(oppositeAngle) * INNER_RADIUS;

        return {
            x: newX,
            y: playerPos.y,  
            z: newZ
        };
    }

    
    function checkPlayerPositions() {
        const players = theEnd.getPlayers({ location: villageCenter, minDistance: OUTER_RADIUS, maxDistance: BORDER_RADIUS });
        if (players.length === 0) return;

        for (const player of players) {
            const playerPos = player.location;

            const newPos = getOppositePosition(playerPos);

            player.camera.fade({
                fadeTime: {
                    fadeInTime: 0.5,
                    holdTime: 0.5,
                    fadeOutTime: 0.5,
                },
                fadeColor: {
                    red: 0,
                    green: 0,
                    blue: 0,
                },
            })

            system.runTimeout(() => {
                player.teleport(newPos);

                
            }, 10)
        }

    }

    
    system.runInterval(checkPlayerPositions, 20);


    

    
    const
        MOON_PARTICLE = "fo_moon2",
        PARTICLE_HEIGHT = 2,
        PARTICLE_DISTANCE = 25,
        SAFE_RADIUS = 30, 
        UPDATE_INTERVAL = 500;

    function spawnMoonInFront(player, allVisitors) {
        const rotation = player.getRotation();
        const yaw = rotation.y * (Math.PI / 180);
        const playerPos = player.location;

        
        const moonPos = {
            x: playerPos.x + Math.sin(yaw) * PARTICLE_DISTANCE,
            y: PARTICLE_HEIGHT,
            z: playerPos.z + Math.cos(yaw) * PARTICLE_DISTANCE
        };

        
        for (const visitor of allVisitors) {
            if (visitor.id === player.id) continue; 

            const dist = Math.sqrt(
                Math.pow(visitor.location.x - moonPos.x, 2) +
                Math.pow(visitor.location.z - moonPos.z, 2)
            );

            if (dist < SAFE_RADIUS) {
                
                return false;
            }
        }

        
        theEnd.runCommand(
            `particle ${MOON_PARTICLE} ${moonPos.x} ${moonPos.y} ${moonPos.z}`
        );
        

        return true;
    }

    system.runInterval(() => {
        const visitors = theEnd.getPlayers({
            location: villageCenter,
            maxDistance: BORDER_RADIUS
        });

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

        
        const targetPlayer = visitors[0];
        const didSpawn = spawnMoonInFront(targetPlayer, visitors);

        
        if (!didSpawn && visitors.length > 1) {
            spawnMoonInFront(visitors[1], visitors);
        }

    }, UPDATE_INTERVAL);

}