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


export function initMinedShaft() {

    const
        FOREBODINGCHECK3 = fo.scoreChapter3, 

        BREAKINGSOUNDINTERVAL = 5, 
        BREAKINTERVAL = BREAKINGSOUNDINTERVAL * 4,
        PLACEINTERVAL = 4,
        CHECKINTERVAL = 2312, 

        KeyCellSize = 128, 
        radius = 28, 
        proximityradius = 16, 
        maxShaftdepth = -54, 
        fillChance = 0.7, 
        resumedelay = Math.floor(7200 / (BREAKINTERVAL + 15)); 

    let
        shaftMineLogicInterval,
        clearTickingAreaFlag = false,
        shaftMineLogicFlag = false,
        resumeTimer = 0;

    
    const
        ACTIVE_SHAFT = "activeShaft",
        SHAFTS_DONE = "shaftsDone";

    const ValidBlocksArray = fo.ValidMinedBlocksArray;

    const validBlocks = new Map(
        ValidBlocksArray.map(b => [b.id, b])
    );

    
    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 getShaftKey(x, z) {
        return `${Math.floor(x / KeyCellSize)}_${Math.floor(z / KeyCellSize)}`; 
    }

    function getShaftsDone() {
        const raw = world.getDynamicProperty(SHAFTS_DONE);
        if (!raw) return {};
        try { return JSON.parse(raw); } catch { return {}; }
    }

    function setShaftsDone(doneObj) {
        world.setDynamicProperty(SHAFTS_DONE, JSON.stringify(doneObj));
    }

    function markShaftComplete(x, z) {
        const key = getShaftKey(x, z);
        const done = getShaftsDone();
        done[key] = true;
        setShaftsDone(done);
    }


    function getBlockData(block) {
        return validBlocks.get(block.typeId);
    }

    
    function getActiveShaft() {
        const raw = world.getDynamicProperty(ACTIVE_SHAFT);
        if (!raw) return null;
        try { return JSON.parse(raw); } catch { return null; }
    }

    function setActiveShaft(data) {
        world.setDynamicProperty(ACTIVE_SHAFT, JSON.stringify(data));
    }

    function clearActiveShaft() {
        world.setDynamicProperty(ACTIVE_SHAFT, "");
    }

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

        system.runTimeout(() => {
            const dropBlockId = new ItemStack(block.typeId, 1);
            block.setType("minecraft:air");
            overworld.playSound(data.brokenSound, blockLoc, {
                volume: 2,
            });
            overworld.spawnItem(dropBlockId, blockLoc);
            system.clearRun(breakingSoundInterval)
        }, BREAKINTERVAL);

    }

    function blockPlacingAction(overworld, block, blockLoc) {
        system.runTimeout(() => {
            block.setType("minecraft:mossy_cobblestone");
            overworld.playSound("dig.stone", blockLoc, {
                volume: 2,
            });
        }, PLACEINTERVAL)

    }

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

    }


    
    system.runInterval(() => {

        if (shaftMineLogicFlag) return;

        const overworld = fo.overworld;
        if (!clearTickingAreaFlag) {
            overworld.runCommand(`tickingarea remove FoMineShaft`)
            clearTickingAreaFlag = true;
        };

        const structuresToggle = fo.minorStructures;
        if (!structuresToggle) return;

        const forebodingScore = fo.forebodingScore;
        if (forebodingScore < FOREBODINGCHECK3) return;

        let shaft = getActiveShaft();

        if (!shaft) {
            
            const players = overworld.getPlayers().filter(p => p.location.y <= 75);
            if (players.length === 0) return;

            const
                player = players[Math.floor(Math.random() * players.length)],
                shaftLocation = getPositionAround(player.location, radius);

            

            const key = getShaftKey(shaftLocation.x, shaftLocation.z);
            const shaftsDone = getShaftsDone();

            if (shaftsDone[key]) {
                
                
                return;
            }

            const
                topMostBlockY = 35 + Math.floor(Math.random() * 35),
                topMostBlock = overworld.getTopmostBlock(shaftLocation, topMostBlockY),
                dirtTopMostBlock = overworld.getBlockBelow(topMostBlock.location, {
                    includeLiquidBlocks: false,
                    includePassableBlocks: false,
                    includeTypes: [
                        "minecraft:dirt",
                        "minecraft:andesite",
                        "minecraft:coal_ore",
                        "minecraft:copper_ore",
                        "minecraft:deepslate",
                        "minecraft:deepslate_coal_ore",
                        "minecraft:deepslate_copper_ore",
                        "minecraft:deepslate_diamond_ore",
                        "minecraft:deepslate_emerald_ore",
                        "minecraft:deepslate_gold_ore",
                        "minecraft:deepslate_iron_ore",
                        "minecraft:deepslate_lapis_ore",
                        "minecraft:deepslate_redstone_ore",
                        "minecraft:lit_deepslate_redstone_ore",
                        "minecraft:diamond_ore",
                        "minecraft:diorite",
                        "minecraft:emerald_ore",
                        "minecraft:gold_ore",
                        "minecraft:granite",
                        "minecraft:iron_ore",
                        "minecraft:lapis_ore",
                        "minecraft:redstone_ore",
                        "minecraft:lit_redstone_ore",
                        "minecraft:stone",
                        "minecraft:tuff",
                    ],
                    maxDistance: 15,
                }); 

            if (!dirtTopMostBlock) return;

            
            
            const
                block00 = dirtTopMostBlock.below(6), 
                block10 = block00.south(1),
                block20 = block00.south(2),
                block01 = block00.east(1),
                block11 = block01.south(1),
                block21 = block01.south(2),
                block02 = block00.east(2),
                block12 = block02.south(1),
                block22 = block02.south(2);


            if (!ValidBlocksArray.some(e =>
                e.id === block00.typeId ||
                e.id === block10.typeId ||
                e.id === block20.typeId ||
                e.id === block01.typeId ||
                e.id === block11.typeId ||
                e.id === block21.typeId ||
                e.id === block02.typeId ||
                e.id === block12.typeId ||
                e.id === block22.typeId)) return;

            shaft = {
                maxDepth: Math.max(dirtTopMostBlock.y - 58 - Math.floor(Math.random() * 40), maxShaftdepth),
                baseX: Math.floor(dirtTopMostBlock.x),
                baseZ: Math.floor(dirtTopMostBlock.z),
                y: dirtTopMostBlock.y - 6,
                done: false,
                offsets: [[0, 0], [1, 0], [2, 0], [0, 1], [1, 1], [2, 1], [0, 2], [1, 2], [2, 2],], 
                offsetIndex: 0,                          
                fillNonAirBlocksCount: 0,
                pyramidBaseX: Math.floor(block11.x), 
                pyramidBaseZ: Math.floor(block11.z), 
                pyramidBaseY: Math.floor(block11.y + 1),
                pyramidlevels: [7, 5, 3],
                pyramidShellBlocks: [],
                pyramidInteriorBlocks: [],
                pyramidAllBlocks: [],
                pyramidPhase: 0, 
                mode: "dig", 
                
                breakInterval: BREAKINTERVAL,
                fillInterval: PLACEINTERVAL
            };

            

            setActiveShaft(shaft);
        }

        

        system.runTimeout(() => {
            overworld.runCommand(`tickingarea add ${shaft.pyramidBaseX - 3} 80 ${shaft.pyramidBaseZ - 3} ${shaft.pyramidBaseX + 3} -60 ${shaft.pyramidBaseZ + 3} FoMineShaft`) 
            shaftMineLogic(shaft, overworld)
        }, 60)

    }, CHECKINTERVAL);


    
    function shaftMineLogic(shaft, overworld) {
        shaftMineLogicFlag = true;
        const delay = shaft.mode === "dig"
            ? shaft.breakInterval
            : shaft.fillInterval;

        shaftMineLogicInterval = system.runInterval(() => {
            shaft = getActiveShaft();

            if (shaft.done) {
                

                
                markShaftComplete(shaft.baseX, shaft.baseZ);

                shaftMineLogicFlag = false;
                overworld.runCommand(`tickingarea remove FoMineShaft`)

                clearActiveShaft();
                system.clearRun(shaftMineLogicInterval);
                return;
            }

            const nearbyPlayers = overworld.getPlayers({
                location: { x: shaft.baseX, y: shaft.y, z: shaft.baseZ },
                maxDistance: proximityradius,
            });

            if (nearbyPlayers.length !== 0 || resumeTimer > 0) {
                if (resumeTimer === 0) resumeTimer = resumedelay;
                resumeTimer--
                
                return
            };

            if (shaft.pyramidPhase !== 0) {
                buildPyramid(overworld, shaft)
                return;
            }

            
            const [dx, dz] = shaft.offsets[shaft.offsetIndex];
            const blockLoc = { x: shaft.baseX + dx, y: shaft.y, z: shaft.baseZ + dz };
            const block = overworld.getBlock(blockLoc);
            if (!block) return;
            const blockTYPEID = block.typeId;


            
            if (shaft.mode === "dig") {

                
                if (block.isLiquid || blockTYPEID === "minecraft:flowing_water" || blockTYPEID === "minecraft:flowing_lava") {
                    shaft.done = true;
                    setActiveShaft(shaft);
                    return;
                }

                
                if (!block.isAir) {

                    const data = getBlockData(block);
                    if (!data) {
                        shaft.done = true;
                        setActiveShaft(shaft);
                        return;
                    }

                    
                    blockBreakingAction(overworld, data, block, blockLoc)

                }

                
                system.runTimeout(() => {
                    shaft.offsetIndex++;
                    if (shaft.offsetIndex >= shaft.offsets.length) {
                        
                        shaft.offsetIndex = 0;
                        shaft.y--;
                    }

                    if (shaft.y < shaft.maxDepth) {
                        if (Math.random() < fillChance) { 
                            shaft.mode = "fill";
                            shaft.fillNonAirBlocksCount = 0,
                                shaft.y++
                            shaftMineLogicFlag = false;
                            system.clearRun(shaftMineLogicInterval); 

                            
                        } else { shaft.done = true }
                    };
                    setActiveShaft(shaft);

                }, delay); 

            } else { 
                
                if (shaft.y >= shaft.pyramidBaseY) {
                    
                    setActiveShaft(shaft);
                    buildPyramid(overworld, shaft)
                    return;
                }

                
                if (!block.isAir) {
                    shaft.fillNonAirBlocksCount++;
                } else if (shaft.offsetIndex !== 4) {
                    blockPlacingAction(overworld, block, blockLoc);
                }

                
                system.runTimeout(() => {
                    shaft.offsetIndex++;
                    if (shaft.offsetIndex >= shaft.offsets.length) {
                        
                        shaft.offsetIndex = 0;

                        if (shaft.fillNonAirBlocksCount >= 6) {
                            shaft.done = true;
                            setActiveShaft(shaft);
                            return;
                        }

                        shaft.fillNonAirBlocksCount = 0; 
                        shaft.y++;
                    }

                    setActiveShaft(shaft);

                }, delay);

            }

        }, delay + 1 + Math.floor(Math.random() * 9))

    };

    

    function buildPyramid(overworld, shaft) {
        if (shaft.pyramidPhase === 0) {
            shaft.pyramidPhase = 1; 
            shaft.offsetIndex = 0;

            
            for (let level = 0; level < shaft.pyramidlevels.length; level++) {
                const size = shaft.pyramidlevels[level];
                const y = shaft.pyramidBaseY + level; 
                const r = Math.floor(size / 2);
                for (let dx = -r; dx <= r; dx++) {
                    for (let dz = -r; dz <= r; dz++) {
                        const absdx = Math.abs(dx), absdz = Math.abs(dz);
                        
                        if (level === shaft.pyramidlevels.length - 1 && dx === 0 && dz === 0) continue; 
                        if (absdx === r || absdz === r) {
                            shaft.pyramidShellBlocks.push({ x: shaft.pyramidBaseX + dx, y: y, z: shaft.pyramidBaseZ + dz });
                        } else {
                            
                            if (level < shaft.pyramidlevels.length - 1) shaft.pyramidInteriorBlocks.push({ x: shaft.pyramidBaseX + dx, y: y, z: shaft.pyramidBaseZ + dz });
                        }
                    }
                }
            }
            shaft.pyramidAllBlocks = [
                ...shaft.pyramidInteriorBlocks,
                ...shaft.pyramidShellBlocks,
            ];

            shaft.pyramidAllBlocks.push({
                x: shaft.pyramidBaseX,
                y: shaft.pyramidBaseY + shaft.pyramidlevels.length - 1,
                z: shaft.pyramidBaseZ
            });

            

            shaft.mode = "dig";
            shaftMineLogicFlag = false;

            setActiveShaft(shaft);

            system.clearRun(shaftMineLogicInterval); 

            return;
        }

        
        
        if (shaft.pyramidPhase === 1) {
            const pyramidBlockLoc = shaft.pyramidAllBlocks.shift();

            if (!pyramidBlockLoc) {
                shaft.pyramidPhase = 2; 

                

                shaft.mode = "fill";
                shaftMineLogicFlag = false;

                setActiveShaft(shaft);

                system.clearRun(shaftMineLogicInterval); 

                return;
            };

            const
                pyramidBlock = overworld.getBlock(pyramidBlockLoc),
                pyramidBlockTYPEID = pyramidBlock.typeId;

            
            if (pyramidBlock.isLiquid || pyramidBlockTYPEID === "minecraft:flowing_water" || pyramidBlockTYPEID === "minecraft:flowing_lava") {
                shaft.done = true;
                setActiveShaft(shaft);
                return;
            }

            
            if (!pyramidBlock.isAir) {

                const data = getBlockData(pyramidBlock);
                if (!data) {
                    shaft.done = true;
                    setActiveShaft(shaft);
                    return;
                }
                
                blockBreakingAction(overworld, data, pyramidBlock, pyramidBlockLoc)

            }

            system.runTimeout(() => setActiveShaft(shaft), shaft.breakInterval);

        }

        
        
        if (shaft.pyramidPhase === 2) {
            const pyramidBlockLoc = shaft.pyramidShellBlocks.shift();

            if (!pyramidBlockLoc) {
                shaft.pyramidPhase = 3; 
                setActiveShaft(shaft);

                

                return;
            };

            const
                pyramidBlock = overworld.getBlock(pyramidBlockLoc);

            
            if (!pyramidBlock || !pyramidBlock.isAir) {
                shaft.fillNonAirBlocksCount++;
            } else blockPlacingAction(overworld, pyramidBlock, pyramidBlockLoc);

            system.runTimeout(() => {

                if (shaft.fillNonAirBlocksCount >= 8) {
                    shaft.done = true;
                    setActiveShaft(shaft);
                    return;
                }

                setActiveShaft(shaft);

            }, shaft.fillInterval)

        };

        
        if (shaft.pyramidPhase === 3) {

            const pyramidBlockLoc = shaft.pyramidInteriorBlocks.shift();

            if (!pyramidBlockLoc) {
                shaft.done = true;
                setActiveShaft(shaft);
                return;
            };

            const
                pyramidBlock = overworld.getBlock(pyramidBlockLoc);

            
            if (!pyramidBlock.isAir && !pyramidBlock.isLiquid && pyramidBlock.typeId !== "minecraft:flowing_water") {
                shaft.fillNonAirBlocksCount++;
            } else waterPlacingAction(overworld, pyramidBlock, pyramidBlockLoc);

            system.runTimeout(() => {

                if (shaft.fillNonAirBlocksCount >= 15) {
                    shaft.done = true;
                    setActiveShaft(shaft);

                    

                    return;
                }

                setActiveShaft(shaft);

            }, shaft.fillInterval)

        };


    }

}
