// scripts/region.js

import { BlockPermutation, system } from '@minecraft/server';
import { resolvePermutation } from './utils.js';
import { getCardinalDirection } from './utils.js';
import { undoMap } from './undo.js';

export const MAX_VOLUME = 89000;

export function computeRegion(player, structureId, offsets, structureSizes) {
    const dir = getCardinalDirection(player);
    let size = structureSizes[structureId];
    if (!size) return { error: "No size registered" };
    if (size[dir]) size = size[dir];

    const base = player.location;
    const ox = Math.floor(base.x + offsets.dx);
    const oy = Math.floor(base.y + offsets.dy);
    const oz = Math.floor(base.z + offsets.dz);

    const min = { x: ox, y: oy, z: oz };
    const max = { x: ox + size.w - 1, y: oy + size.h - 1, z: oz + size.l - 1 };

    const volume = size.w * size.h * size.l;
    if (volume > MAX_VOLUME) return { error: `Region too large (${volume})` };

    return { min, max };
}

// NEW: Small structures - immediate snapshot
export function snapshotRegionSync(dim, min, max) {
    const out = [];
    for (let y = min.y; y <= max.y; y++) {
        for (let z = min.z; z <= max.z; z++) {
            for (let x = min.x; x <= max.x; x++) {
                try {
                    const b = dim.getBlock({ x, y, z });
                    if (!b) continue;
                    const perm = b.permutation;
                    out.push({
                        x, y, z,
                        typeId: perm.type.id,
                        states: (perm.getAllStates && perm.getAllStates()) || {},
                    });
                } catch {}
            }
        }
    }
    return out;
}

// NEW: Large structures - background chunked snapshot
export function startAsyncSnapshot(playerId, dim, min, max, player) {
    const blocks = [];
    const total = (max.x - min.x + 1) * (max.y - min.y + 1) * (max.z - min.z + 1);
    let processed = 0;

    // Put placeholder in undoMap
    undoMap.set(playerId, {
        dimId: dim.id,
        blocks,
        min,
        max,
        isLoading: true,
        timestamp: Date.now()
    });

    function processChunk() {
        const start = Date.now();

        // Process up to 50ms per tick to keep world responsive
        while (Date.now() - start < 50 && processed < total) {
            const x = min.x + (processed % (max.x - min.x + 1));
            const y = min.y + Math.floor((processed / (max.x - min.x + 1)) % (max.y - min.y + 1));
            const z = min.z + Math.floor(processed / ((max.x - min.x + 1) * (max.y - min.y + 1)));

            try {
                const b = dim.getBlock({ x, y, z });
                if (b && b.permutation.type.id !== "minecraft:air") {
                    blocks.push({
                        x, y, z,
                        typeId: b.permutation.type.id,
                        states: (b.permutation.getAllStates && b.permutation.getAllStates()) || {},
                    });
                }
            } catch {}

            processed++;
        }

        if (processed >= total) {
            // Mark ready
            const rec = undoMap.get(playerId);
            if (rec) rec.isLoading = false;
            try { player.sendMessage?.("§aUndo data ready!"); } catch {}
        } else {
            system.runTimeout(processChunk, 1);
        }
    }

    processChunk();
}

export function snapshotRegion(dim, min, max) {
    const out = [];
    for (let y = min.y; y <= max.y; y++) {
        for (let z = min.z; z <= max.z; z++) {
            for (let x = min.x; x <= max.x; x++) {
                const b = dim.getBlock({ x, y, z });
                if (!b) continue;
                const perm = b.permutation;
                out.push({
                    x, y, z,
                    typeId: perm.type.id,
                    states: (perm.getAllStates && perm.getAllStates()) || {},
                });
            }
        }
    }
    return out;
}

export function restoreRegion(dim, snapshot) {
    for (const s of snapshot) {
        const b = dim.getBlock({ x: s.x, y: s.y, z: s.z });
        if (!b) continue;
        try {
            let p = resolvePermutation(s.typeId, s.states || {});
            const currentStates = p.getAllStates?.() || {};
            if ("waterlogged" in currentStates && currentStates["waterlogged"] !== false) {
                p = p.withState("waterlogged", false);
            }
            b.setPermutation(p);
        } catch {
            try { b.setPermutation(resolvePermutation("minecraft:air", {})); } catch {}
        }
    }
}

export function clearWaterBlocks(dim, min, max) {
    for (let y = min.y; y <= max.y; y++) {
        for (let z = min.z; z <= max.z; z++) {
            for (let x = min.x; x <= max.x; x++) {
                const blk = dim.getBlock({ x, y, z });
                if (!blk) continue;
                const perm = blk.permutation;
                const isWater =
                    (perm?.matches && (perm.matches("minecraft:water") || perm.matches("minecraft:flowing_water"))) ||
                    perm?.type?.id === "minecraft:water";
                if (isWater) {
                    try { blk.setPermutation(BlockPermutation.resolve("minecraft:air")); } catch {}
                }
            }
        }
    }
}

export function removeEntitiesInBox(dim, min, max) {
    const center = {
        x: (min.x + max.x) / 2,
        y: (min.y + max.y) / 2,
        z: (min.z + max.z) / 2,
    };
    const radius = Math.max(max.x - min.x, max.y - min.y, max.z - min.z) / 2 + 1;
    try {
        const entities = dim.getEntities({ location: center, maxDistance: Math.max(1, radius) });
        for (const e of entities) {
            if (e.typeId === "minecraft:player") continue;
            const p = e.location;
            if (!p) continue;
            if (
                p.x >= min.x && p.x <= max.x &&
                p.y >= min.y && p.y <= max.y &&
                p.z >= min.z && p.z <= max.z
            ) {
                try { e.remove(); } catch {}
            }
        }
    } catch {}
}