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


export function initOnJoin() {

    const
        forebodingScoreCheck3 = fo.scoreChapter3,
        forebodingScoreCheck4 = fo.scoreChapter4,
        forebodingScoreCheck5 = fo.scoreChapter5,
        FOREBODINGCHECK7 = fo.scoreChapter7s, 
        cameraFlickerChance = 1 / 13, 
        screamChance = 1 / 25, 
        possessionSignalChance = 1 / 2, 
        possessionChapt03MinElapsedTime = 432000, 
        possessionChapt04MinElapsedTime = 144000; 


    let stopMusicIntervalId;
    let playExcuseTimeoutId;

    world.afterEvents.playerSpawn.subscribe((eventData) => {
        let { player, initialSpawn } = eventData;

        let worldTime = world.getAbsoluteTime();
        

        if (initialSpawn) {
            
            
            player.runCommand(`fog @s remove Fog`);
            player.runCommand(`fog @s remove FogF`);
            player.runCommand(`fog @s remove FogR`);
            
            player.runCommand(`camera @s clear`);
            
            player.runCommand(`scoreboard players set ${player.name} Foreboding 0`);


            
            let forebodingScore = fo.forebodingScore;

            const ExpectedTicksPassed = realTimePassed();

            system.runTimeout(() => { musicBan(player, forebodingScore) }, 100);

            
            if (forebodingScore > forebodingScoreCheck5) {
                let
                    savedPyramidData = world.getDynamicProperty("mainPyramid"),
                    pyramidData = savedPyramidData ? JSON.parse(savedPyramidData) : false;

                if (pyramidData.paused && ExpectedTicksPassed > 216000) { 
                    system.runTimeout(() => {
                        mossyPyramidReveal(player, pyramidData);
                    }, 25)
                    return; 
                }
            }

            
            system.runTimeout(() => { wandererEventSafeGuard(player, forebodingScore); }, 20)

            
            if (forebodingScore >= forebodingScoreCheck3 && Math.random() < (cameraFlickerChance * fo.probabilityModifier)) {
                cameraFlicker(player);
            };

            
            if (forebodingScore >= forebodingScoreCheck4 && Math.random() < screamChance) {
                system.runTimeout(() => {
                    scream(player);
                }, 320)
            };

            
            forebearerHandle(player);

            
            if (forebodingScore >= forebodingScoreCheck4 && Math.random() < possessionSignalChance) {
                system.runTimeout(() => { possessionSignals(player, forebodingScore, ExpectedTicksPassed) }, 5);
            };

        }


        if (!initialSpawn) wandererEventSafeGuard(player);

        if (!initialSpawn && worldTime > 12000) return;

        
        if (!initialSpawn && worldTime < 12000) {
            world.gameRules.doMobSpawning = true;
            
            if (stopMusicIntervalId) {
                system.clearRun(stopMusicIntervalId);
                stopMusicIntervalId = null;
            }

            
            if (playExcuseTimeoutId) {
                system.clearRun(playExcuseTimeoutId);
                playExcuseTimeoutId = null;
            }

            
        };

        if (initialSpawn && worldTime < 300) {
            

            
            let spawnX = player.location.x;
            let spawnY = Math.floor(player.location.y) - 5; 
            let spawnZ = player.location.z;
            let dimension = player.dimension;

            
            system.runTimeout(() => {
                let targetY = spawnY; 
                let targetX = spawnX;
                let targetZ = spawnZ;
                let foundValidSpot = false;

                
                let maxAttempts = 80;
                for (let i = 0; i < maxAttempts; i++) {
                    
                    let y = spawnY - i; 
                    if (y <= -20) break; 

                    
                    for (let dx = -1; dx <= 2; dx++) {
                        for (let dz = -1; dz <= 2; dz++) {
                            let blockAbove = dimension.getBlock({ x: spawnX + dx, y: y, z: spawnZ + dz });
                            let blockMid = dimension.getBlock({ x: spawnX + dx, y: y - 1, z: spawnZ + dz });
                            let blockBelow = dimension.getBlock({ x: spawnX + dx, y: y - 2, z: spawnZ + dz });

                            
                            if (blockAbove.isAir && blockMid.isAir && !blockBelow.isAir) {
                                targetY = y - 1; 
                                targetX = spawnX + dx
                                targetZ = spawnZ + dz
                                foundValidSpot = true;
                                break;
                            }
                        }
                        if (foundValidSpot) break;
                    }
                    if (foundValidSpot) break;
                }

                if (foundValidSpot) {
                    
                    player.teleport({ x: targetX, y: targetY, z: targetZ }, dimension);

                    world.gameRules.doMobSpawning = false; 

                    
                    system.runTimeout(() => {
                        world.gameRules.doMobSpawning = true;
                    }, 12000
                    )

                    
                    system.run(stopGameMusic);

                    
                    playExcuseTimeoutId = system.runTimeout((playExcuse), 6000);

                } else {
                    
                }
            }, 20); 
        } else {
            
            if (worldTime < 12300) { 
                world.gameRules.doMobSpawning = true;
                

                
                let players = world.getPlayers();
                for (let player of players) {
                    
                    let playerLocation = player.location.y;

                    
                    if (playerLocation < 30) {
                        const spawnLocation = world.getDefaultSpawnLocation();
                        const overworld = fo.overworld;

                        
                        let validY = findValidYAtSpawn(overworld, spawnLocation.x, spawnLocation.z);

                        if (validY !== null) {
                            player.teleport(
                                { x: spawnLocation.x, y: validY, z: spawnLocation.z },
                                overworld
                            );
                            
                        } else {
                            
                        }
                    }
                }
            }
        }
    });
















    

    
    function findValidYAtSpawn(dimension, spawnX, spawnZ) {
        
        for (let y = 80; y >= 40; y--) {
            let blockAbove = dimension.getBlock({ x: spawnX, y: y, z: spawnZ });
            let blockMid = dimension.getBlock({ x: spawnX, y: y - 1, z: spawnZ });
            let blockBelow = dimension.getBlock({ x: spawnX, y: y - 2, z: spawnZ });

            
            if (blockAbove && blockMid && blockBelow) {
                
                if (blockAbove.isAir && blockMid.isAir && !blockBelow.isAir) {
                    return y - 1; 
                }
            }
        }
        return null;
    };

    
    function stopGameMusic() {
        const overworld = fo.overworld;

        
        const stopSoundCommands = [
            "stopsound @a music.game",
            "stopsound @a music.game.basalt_deltas",
            "stopsound @a music.game.creative",
            "stopsound @a music.game.crimson_forest",
            "stopsound @a music.game.dripstone_caves",
            "stopsound @a music.game.endboss",
            "stopsound @a music.game.frozen_peaks",
            "stopsound @a music.game.grove",
            "stopsound @a music.game.jagged_peaks",
            "stopsound @a music.game.lush_caves",
            "stopsound @a music.game.meadow",
            "stopsound @a music.game.nether",
            "stopsound @a music.game.nether_wastes",
            "stopsound @a music.game.snowy_slopes",
            "stopsound @a music.game.soul_sand_valley",
            "stopsound @a music.game.soulsand_valley",
            "stopsound @a music.game.stony_peaks",
            "stopsound @a music.game.warped_forest",
            "stopsound @a music.game.water",
            "stopsound @a music.menu",
            "stopsound @a music.game.swamp_music",
            "stopsound @a music.game_and_wild_equal_chance",
            "stopsound @a music.game_and_wild_favor_game",
            "stopsound @a music.game.deep_dark",
            "stopsound @a music.overworld.bamboo_jungle",
            "stopsound @a music.overworld.cherry_grove",
            "stopsound @a music.overworld.flower_forest",
            "stopsound @a music.overworld.jungle",
            "stopsound @a music.overworld.jungle_edge",
            "stopsound @a music.overworld.desert",
            "stopsound @a music.overworld.mesa"
        ];

        let currentIndex = 0; 

        
        const stopMusicIntervalId = system.runInterval(() => {
            const worldTime = world.getAbsoluteTime();

            
            if (worldTime >= 12000) {
                system.clearRun(stopMusicIntervalId);
                return;
            }

            
            for (let i = 0; i < 4; i++) {
                if (currentIndex >= stopSoundCommands.length) {
                    currentIndex = 0; 
                }

                const command = stopSoundCommands[currentIndex];
                overworld.runCommand(command); 
                currentIndex++;
            }
        }, 1); 
    }

    
    function playExcuse() {

        world.playMusic("excuse2", { volume: 0.3, });

    };

    
    function teleportPlayerBack(player) {
        let originalD = player.getDynamicProperty("dimension");
        let dimensionId = world.getDimension(originalD);
        let originalPos = player.getDynamicProperty("saved_position");

        if (originalPos !== undefined && originalD !== undefined) {
            player.teleport(originalPos, { dimension: dimensionId });
            player.setDynamicProperty("hasBeenTeleported", false);
        }
    }

    function wandererEventSafeGuard(player) {
        
        let hasBeenTeleported = player.getDynamicProperty("hasBeenTeleported");
        if (hasBeenTeleported) {
            teleportPlayerBack(player);
        }
    };

    
    function cameraFlicker(player) {
        const flickerCount = 12; 
        const flickerDuration = 0.25; 
        const delayBetweenFlickers = flickerDuration * 2 * 20; 

        for (let i = 0; i < flickerCount; i++) {
            
            const fadeColor = i % 2 === 0 ? { red: 1, green: 1, blue: 1 } : { red: 0, green: 0, blue: 0 }; 

            system.runTimeout(() => {
                player.camera.fade({
                    fadeTime: {
                        fadeInTime: 0, 
                        holdTime: flickerDuration * 0.5, 
                        fadeOutTime: 0, 
                    },
                    fadeColor: fadeColor, 
                });
            }, i * delayBetweenFlickers); 
        }
    }

    

    function scream(player) {

        const
            SOUND = "fo_mob.ghast.scream",
            SOUND_VOLUME = 8,
            SOUND_PITCH = 0.3,
            SOUND_MIN_DISTANCE = 100;

        let validLocation = null;

        const
            angle = Math.random() * Math.PI * 2,
            distance = SOUND_MIN_DISTANCE, 
            dx = Math.cos(angle) * distance,
            dz = Math.sin(angle) * distance,

            x = player.location.x + dx,
            z = player.location.z + dz,
            y = 65;

        validLocation = { x, y, z };

        if (validLocation) {
            player.playSound(SOUND, { location: validLocation, volume: SOUND_VOLUME, pitch: SOUND_PITCH });
            
        } else {
            
        }
    }


    
    function forebearerHandle(player) {
        const playerName = player.nameTag;
        const playerDim = player.dimension;

        if (!playerName) return;

        let stored = world.getDynamicProperty("forebearerDead") || "[]";
        let storedArr = JSON.parse(stored);

        const index = storedArr.indexOf(playerName);
        if (index >= 0) {
            const playerGM = player.getGameMode()
            
            system.runTimeout(() => {
                if (playerGM !== "Survival" && playerGM !== "Adventure") {
                    player.setGameMode("Survival");
                    system.runTimeout(() => { player.setGameMode(playerGM); }, 1)
                }
                player.kill()
            }, 10)

            
            storedArr.splice(index, 1);

            
            world.setDynamicProperty("forebearerDead", JSON.stringify(storedArr));
        } else {
            const forebearer = playerDim.getEntities({
                name: playerName,
                type: "fo:forebearer"
            })[0];

            if (!forebearer) return;
            const forebearerLoc = forebearer.location;


            system.runTimeout(() => { player.teleport(forebearerLoc) }, 1)

            world.scoreboard.getObjective("Online").removeParticipant(playerName)

            forebearer.remove()

        }
    }

    function musicBan(player, forebodingScore) {
        forebodingScore = fo.forebodingScore;

        if (forebodingScore > forebodingScoreCheck3) {
            player.playMusic("forefeelM", { fade: 10, volume: 0.01, loop: true });
            
        }

        if (forebodingScore < FOREBODINGCHECK7) {
            player.playMusic("phurpa", { fade: 10, loop: true, volume: 0.01, });
            
        }
    }


















    

    

    function realTimePassed() {
        let lastRealTime = world.getDynamicProperty("lastRealTime"),
            currentRealTime = Date.now();

        
        const actualTimePassed = currentRealTime - lastRealTime;
        const ExpectedTicksPassed = Math.round(actualTimePassed / 50);

        return ExpectedTicksPassed;

    };

    function SlightlyMoveAround(player) {

        player.runCommand(`spreadplayers ~ ~ 1 10 @s ~3`);


    }

    function HungerProgression(player) {

        const hungerComp = player.getComponent("minecraft:player.hunger");
        const saturationComp = player.getComponent("minecraft:player.saturation");

        const newFoodLevel = Math.max(2, hungerComp.currentValue - 4 - Math.floor(Math.random() * 14));

        hungerComp.setCurrentValue(newFoodLevel);
        saturationComp.setCurrentValue(0);

        

    }

    function HealthDecay(player) {
        const health = player.getComponent("health");

        const newHealth = Math.max(3, health.currentValue - 2 - Math.floor(Math.random() * 15));
        health.setCurrentValue(newHealth);

        

    };

    function MossyCobblestoneMine(player) {

        const
            inventoryContainer = player.getComponent("inventory").container,

            mossyCoblestone1 = new ItemStack("mossy_cobblestone", Math.floor(Math.random() * 64 + 1)),
            mossyCoblestone2 = new ItemStack("mossy_cobblestone", Math.floor(Math.random() * 64 + 1));

        inventoryContainer.addItem(mossyCoblestone1)
        inventoryContainer.addItem(mossyCoblestone2)


    }

    function MossyCobblestoneMainHand(player) {

        const
            inventoryContainer = player.getComponent("inventory").container,

            equippableComp = player.getComponent("equippable"),
            currentMainHandItem = equippableComp.getEquipment(EquipmentSlot.Mainhand),

            mossyCoblestone = new ItemStack("mossy_cobblestone", Math.floor(Math.random() * 64 + 1));

        if (currentMainHandItem) inventoryContainer.addItem(currentMainHandItem);
        equippableComp.setEquipment(EquipmentSlot.Mainhand, mossyCoblestone);

    }

    function equipmentDurabilityLoss(player) {
        const

            equippableComp = player.getComponent("equippable"),

            headEquipment = equippableComp.getEquipment(EquipmentSlot.Head),
            chestEquipment = equippableComp.getEquipment(EquipmentSlot.Chest),
            legsEquipment = equippableComp.getEquipment(EquipmentSlot.Legs),
            feetEquipment = equippableComp.getEquipment(EquipmentSlot.Feet);
        

        if (headEquipment) {
            const headEquipmentDurComp = headEquipment.getComponent(ItemComponentTypes.Durability);
            const newDamage = Math.min(headEquipmentDurComp.maxDurability - 1, headEquipmentDurComp.damage + Math.floor(Math.random() * 20) + 5);
            headEquipmentDurComp.damage = newDamage;
            equippableComp.setEquipment(EquipmentSlot.Head, headEquipment);

            

        };
        if (chestEquipment) {
            const chestEquipmentDurComp = chestEquipment.getComponent(ItemComponentTypes.Durability);
            const newDamage = Math.min(chestEquipmentDurComp.maxDurability - 1, chestEquipmentDurComp.damage + Math.floor(Math.random() * 20) + 5);
            chestEquipmentDurComp.damage = newDamage;
            equippableComp.setEquipment(EquipmentSlot.Chest, chestEquipment);

            

        };
        if (legsEquipment) {
            const legsEquipmentDurComp = legsEquipment.getComponent(ItemComponentTypes.Durability);
            const newDamage = Math.min(legsEquipmentDurComp.maxDurability - 1, legsEquipmentDurComp.damage + Math.floor(Math.random() * 20) + 5);
            legsEquipmentDurComp.damage = newDamage;
            equippableComp.setEquipment(EquipmentSlot.Legs, legsEquipment);

            

        };
        if (feetEquipment) {
            const feetEquipmentDurComp = feetEquipment.getComponent(ItemComponentTypes.Durability);
            const newDamage = Math.min(feetEquipmentDurComp.maxDurability - 1, feetEquipmentDurComp.damage + Math.floor(Math.random() * 20) + 5);
            feetEquipmentDurComp.damage = newDamage;
            equippableComp.setEquipment(EquipmentSlot.Feet, feetEquipment);

            
        };

    };

    function mossyPyramidReveal(player, pyramidData) {

        
        player.teleport({ x: pyramidData.pausedx - 0.22, y: pyramidData.pausedy, z: pyramidData.pausedz + 0.11 }, {
            facingLocation: { x: pyramidData.pausedx, y: pyramidData.pausedy - 0.7, z: pyramidData.pausedz + 0.3 },
            dimension: fo.overworld,
        })

        HungerProgression(player);
        HealthDecay(player);
        MossyCobblestoneMine(player);
        equipmentDurabilityLoss(player);
        MossyCobblestoneMainHand(player);

        pyramidData.paused = false; 
        savePyramidData(pyramidData)
    };

    function savePyramidData(pyramidData) {
        world.setDynamicProperty("mainPyramid", JSON.stringify(pyramidData));
    }


    function possessionSignals(player, forbodingScore, ExpectedTicksPassed) {

        
        if (ExpectedTicksPassed < possessionChapt04MinElapsedTime || ExpectedTicksPassed < possessionChapt03MinElapsedTime && forbodingScore < forebodingScoreCheck4) return;


        const playersNearby = player.dimension.getPlayers({
            location: player.location,
            excludeNames: [player.name],
            maxDistance: 256
        })

        if (playersNearby.length > 0) return;

        if (Math.random() < 0.5) SlightlyMoveAround(player);
        if (Math.random() < 0.5) HungerProgression(player);
        if (Math.random() < 0.3) HealthDecay(player);
        if (Math.random() < 0.3) MossyCobblestoneMine(player);
        if (Math.random() < 0.3) equipmentDurabilityLoss(player);

        


    }

}