import { BlockPermutation, world } from "@minecraft/server";
import { replaySessions } from "../data/replay-player-session";
import { isChunkLoaded } from "./is-chunk-loaded";
import { waitForChunkLoad } from "./wait-for-chunk-load";
import { debugError, debugWarn } from "../data/util/debug";
export async function loadBlocksUpToTick(targetTick, player) {
    const session = replaySessions.playerSessions.get(player.id);
    if (!session) {
        debugWarn(`No replay session found for player ${player.name}`);
        return;
    }
    const playerData = session.replayBlockStateMap.get(player.id);
    if (!playerData) {
        debugWarn(`No block replay data for player ${player.name}`);
        return;
    }
    const blockBreaks = session.replayBlockInteractionAfterMap.get(player.id);
    async function setBlock(location, typeId, states) {
        if (!isChunkLoaded(location, player)) {
            debugWarn(`Chunk not loaded for block at ${location.x}, ${location.y}, ${location.z}. Teleporting player...`);
            const success = player.tryTeleport({ x: location.x, y: location.y + 2, z: location.z }, { checkForBlocks: false });
            if (success) {
                await waitForChunkLoad(location, player);
            }
            else {
                debugError(`Failed to teleport ${player.name} to load chunk at ${location.x}, ${location.y}, ${location.z}`);
                return;
            }
        }
        const dimension = world.getDimension(session.replayController.dimension.id);
        const block = dimension.getBlock(location);
        if (!block) {
            debugError(`Failed to get block at ${location.x}, ${location.y}, ${location.z}`);
            return;
        }
        block.setPermutation(BlockPermutation.resolve(typeId, states));
    }
    for (let tick = 0; tick <= targetTick; tick++) {
        // Handle block breaks first
        const breakEntry = blockBreaks?.blockSateAfterInteractions[tick];
        if (breakEntry) {
            if ("lowerPart" in breakEntry && "upperPart" in breakEntry) {
                await setBlock(breakEntry.lowerPart.location, breakEntry.lowerPart.typeId, breakEntry.lowerPart.states);
                await setBlock(breakEntry.upperPart.location, breakEntry.upperPart.typeId, breakEntry.upperPart.states);
            }
            else if ("thisPart" in breakEntry && "otherPart" in breakEntry) {
                await setBlock(breakEntry.thisPart.location, breakEntry.thisPart.typeId, breakEntry.thisPart.states);
                await setBlock(breakEntry.otherPart.location, breakEntry.otherPart.typeId, breakEntry.otherPart.states);
            }
            else if ("location" in breakEntry) {
                await setBlock(breakEntry.location, breakEntry.typeId, breakEntry.states);
            }
        }
        // Then handle block placements
        const blockData = playerData.blockStateChanges[tick];
        if (!blockData)
            continue;
        if (blockData.lowerPart && blockData.upperPart) {
            await setBlock(blockData.lowerPart.location, blockData.lowerPart.typeId, blockData.lowerPart.states);
            await setBlock(blockData.upperPart.location, blockData.upperPart.typeId, blockData.upperPart.states);
        }
        else if (blockData.thisPart && blockData.otherPart) {
            await setBlock(blockData.thisPart.location, blockData.thisPart.typeId, blockData.thisPart.states);
            await setBlock(blockData.otherPart.location, blockData.otherPart.typeId, blockData.otherPart.states);
        }
        else if (blockData.location) {
            await setBlock(blockData.location, blockData.typeId, blockData.states);
        }
    }
}
