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




export function initMirrorWorld() {


    
    if (!world.getDynamicProperty("netherPyramid")) {
        world.setDynamicProperty("netherPyramid", false); 
    }

    
    const
        mirrorWorldCenter = { x: 100272, y: 62, z: 100256 }, 
        nether = fo.nether,
        INNER_RADIUS = 122,
        OUTER_RADIUS = 142,
        BORDER_RADIUS = 200;


    const blockType = "minecraft:mossy_cobblestone";
    const blockType2 = "minecraft:waxed_oxidized_copper_door";
    const fillBlockType = "minecraft:water";

    
    nether.runCommand(`/tickingarea remove foMirrorWorldCenter`);

    
    let
        currentLayer = 125, 
        exteriorInterval,
        fillInterval,
        pyramidBlockPlaceAttempt = 0;


    
    const stopSoundCommands = [
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.basalt_deltas.additions`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.basalt_deltas.loop`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.basalt_deltas.mood`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.crimson_forest.additions`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.crimson_forest.loop`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.crimson_forest.mood`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.nether_wastes.additions`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.nether_wastes.loop`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.nether_wastes.mood`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.soulsand_valley.additions`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.soulsand_valley.loop`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.soulsand_valley.mood`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.warped_forest.additions`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.warped_forest.loop`,
        `execute positioned ${mirrorWorldCenter.x} ${mirrorWorldCenter.y} ${mirrorWorldCenter.z} run stopsound @a [r=300] ambient.warped_forest.mood`
    ];

    let
        currentIndex = 0, 
        currentVisitors = new Set(), 
        mirrorWorldEventFlag = false, 

        
        savedNetherPyramid = world.getDynamicProperty("netherPyramid"),
        progress = savedNetherPyramid ? JSON.parse(savedNetherPyramid) : {
            x: mirrorWorldCenter.x,
            z: mirrorWorldCenter.z,
            size: 95,
            height: 47,
            stage: "building", 
            currentY: 125, 
            step: 0,
            fillLayer: 125 - 47, 
            blocksSinceLastSave: 0,
            saveThreshold: fo.performanceModifier === 1 ? 2 : fo.performanceModifier === 1.5 ? 3 : fo.performanceModifier === 2.5 ? 4 : 5
        },
        pyramidBuilt = progress.stage === "complete", 

        executeCommandsInterval,
        checkPlayerPositionsInterval,
        solitaryDoorInterval;

    
    system.runInterval(() => {

        
        
        

        updateVisitors();

        
        if (currentVisitors.size > 0 && !mirrorWorldEventFlag) {

            MirrorWorldStarts();

            if (!pyramidBuilt) {
                nether.runCommand(`/tickingarea add ${mirrorWorldCenter.x - 48} 0 ${mirrorWorldCenter.z - 48} ${mirrorWorldCenter.x + 48} 0 ${mirrorWorldCenter.z + 48} foMirrorWorldCenter`);

                saveProgress(true)
                startPyramidBuild();
                
            };

            mirrorWorldEventFlag = true;

        }

        if (currentVisitors.size === 0 && mirrorWorldEventFlag) {

            if (exteriorInterval !== undefined) system.clearRun(exteriorInterval);
            if (fillInterval !== undefined) system.clearRun(fillInterval);
            if (executeCommandsInterval !== undefined) system.clearRun(executeCommandsInterval);
            if (checkPlayerPositionsInterval !== undefined) system.clearRun(checkPlayerPositionsInterval);

            

            mirrorWorldEventFlag = false;
        }

    }, 77) 


    function MirrorWorldStarts() {
        
        
        executeCommandsInterval = system.runInterval(executeCommands, 1); 
        
        checkPlayerPositionsInterval = system.runInterval(checkPlayerPositions, 20);

        solitaryDoorInterval = system.runInterval(solitaryDoor, 4);

    }

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

            const command = stopSoundCommands[currentIndex];
            nether.runCommand(command); 
            currentIndex++;
        }
    }

    
    function checkPlayerPositions() {
        const players = nether.getPlayers({ location: mirrorWorldCenter, 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)
        }

    }

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

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

        
        const oppositeAngle = angle + Math.PI;

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

        const topMostBlock = nether.getTopmostBlock({ x: newX, z: newZ }, 127);

        return {
            x: newX,
            y: topMostBlock.y + 1,  
            z: newZ
        };
    }

    
    
    function solitaryDoor() {
        if (!pyramidBuilt) return;

        const block = nether.getBlock({ x: mirrorWorldCenter.x, y: 126, z: mirrorWorldCenter.z });
        

        if (!block) { 

            
            return;

        } else if (block.typeId != blockType2 && pyramidBuilt) {
            nether.runCommand(`setblock ${mirrorWorldCenter.x} ${126} ${mirrorWorldCenter.z} ${blockType2}`); 
            

            return;
        }

        const isOpen = block.permutation.getState("open_bit"); 
        const players = nether.getPlayers({ location: { x: mirrorWorldCenter.x, y: 126, z: mirrorWorldCenter.z }, maxDistance: 2 })

        
        if (isOpen && players.length > 0) {
            let
                savedPyramidData = world.getDynamicProperty("mainPyramid"),
                pyramidData = savedPyramidData ? JSON.parse(savedPyramidData) : false;

            if (!pyramidData || pyramidData.stage !== "complete") return;

            for (const player of players) {
                world.setDynamicProperty("mirrorWorldDoorTp", true);

                player.setSpawnPoint({
                    dimension: fo.overworld,
                    x: pyramidData.x,
                    y: 106,
                    z: pyramidData.z,
                })

                player.teleport({ x: pyramidData.x, y: 106, z: pyramidData.z }, {
                    dimension: fo.overworld,
                });
            }
        };

    };




    

    
    function saveProgress(forceSave = false) {
        progress.blocksSinceLastSave++;

        if (forceSave || progress.blocksSinceLastSave >= progress.saveThreshold) {
            world.setDynamicProperty("netherPyramid", JSON.stringify(progress));
            progress.blocksSinceLastSave = 0;
        }
    };

    function startPyramidBuild() {
        exteriorInterval = system.runInterval(() => {
            if (currentVisitors.size === 0) return;

            if (progress.stage === "filling") {
                saveProgress(true);
                startInteriorFill();
                system.clearRun(exteriorInterval);
                return;
            }

            buildPyramidStep();

        }, 2);
    };

    function buildPyramidStep() {
        const { x, z, size, height, currentY, step } = progress;
        const center = mirrorWorldCenter;

        
        const layer = 125 - currentY; 

        if (layer >= height) {
            progress.stage = "filling";
            saveProgress(true);
            return;
        }

        
        
        const layerSize = size - layer * 2;

        if (layerSize <= 0) {
            progress.stage = "filling";
            saveProgress(true);
            return;
        }

        const half = Math.floor(layerSize / 2);
        const y = currentY; 

        
        const perimeterCount = layerSize * 4 - 4;

        if (step <= perimeterCount) {
            const i = step;
            let dx, dz;

            
            if (i < layerSize) { dx = -half + i; dz = -half; }
            else if (i < layerSize * 2 - 1) { dx = half; dz = -half + (i - layerSize + 1); }
            else if (i < layerSize * 3 - 2) { dx = half - (i - (layerSize * 2 - 1)); dz = half; }
            else { dx = -half; dz = half - (i - (layerSize * 3 - 2)); }

            const blockPos = {
                x: center.x + dx,
                y: y,
                z: center.z + dz
            };

            try {
                const block = nether.getBlock(blockPos);
                if (block?.typeId !== blockType) {
                    block?.setType(blockType);
                    nether.playSound("dig.stone", blockPos, { volume: 2, pitch: 0.8 + Math.random() * 0.4 });
                }
            } catch (e) {
                console.warn(`Error placing block at ${blockPos.x},${blockPos.y},${blockPos.z}: ${e}`);
            }

            progress.step++;
            saveProgress();
            return;
        }

        
        progress.currentY--;
        progress.step = 0;
        saveProgress();
    }

    function startInteriorFill() {

        
        fillInterval = system.runInterval(() => {
            if (currentVisitors.size === 0) return;

            if (progress.fillLayer > 125) {
                
                pyramidBuilt = true;

                progress.stage = "complete";
                saveProgress(true);

                nether.runCommand(`/tickingarea remove foMirrorWorldCenter`);
                system.clearRun(fillInterval);
                return;
            }

            
            const layer = progress.fillLayer - (125 - progress.height);
            const layerSize = progress.size - (progress.height - layer) * 2;

            if (layerSize > 2) {
                const half = Math.floor(layerSize / 2);
                const from = {
                    x: mirrorWorldCenter.x - half + 1,
                    y: progress.fillLayer,
                    z: mirrorWorldCenter.z - half + 1
                };
                const to = {
                    x: mirrorWorldCenter.x + half - 1,
                    y: progress.fillLayer,
                    z: mirrorWorldCenter.z + half - 1
                };

                try {
                    const water = BlockPermutation.resolve("minecraft:water");
                    nether.fillBlocks(new BlockVolume(from, to), water);
                } catch (e) {
                    console.warn(`Fill command error: ${e}`);
                }
            }

            progress.fillLayer++;
            saveProgress();
        }, 10);
    }




















    


    
    
    
    
    
    function updateVisitors() {

        const newVisitorList = nether.getPlayers({ location: mirrorWorldCenter, maxDistance: BORDER_RADIUS });
        const newVisitors = new Set(newVisitorList.map(p => p.id));

        
        for (const visitorId of currentVisitors) {
            if (!newVisitors.has(visitorId)) {
                const player = [...world.getPlayers()].find(p => p.id === visitorId);
                if (player) {
                    player.runCommand(`fog @s remove Fog`); 
                    
                }
            }
        }

        
        for (const player of newVisitorList) {
            if (!currentVisitors.has(player.id)) {
                player.playMusic("phurpa", { 
                    fade: 10,
                    loop: true,
                    volume: 0.01,
                });
                player.runCommand(`fog @s push foreboding:fog08b Fog`); 
                
            }
        }

        currentVisitors = newVisitors;


    }



}