import { Direction, ItemStack, system } from "@minecraft/server";
import { EntityTracker } from "./util/entityTracker";
import { suppEvents } from "./suppEventHandler";
import { SuppEntities } from "./reg/suppEntities";
import { getBlockSafe, stateToString, stringToState } from "./util/miscUtils";
import { McBlocks } from "./reg/mcBlocks";
import { SuppStates } from "./reg/suppStates";
import { offsetVec } from "./util/dirUtils";
import { isReplaceable } from "./util/blockProperties";
class FallingBlocksManager extends EntityTracker {
    constructor() {
        super();
        this.fallingBlockTag = "razz_sup:falling_block";
        this.fallingBlocks = new Map();
        suppEvents.subscribeOnNeighborChanged((event) => {
            if (event.fromDir == Direction.Down) {
                const block = event.block;
                if (this.fall(block, event.neighborBlock)) {
                    suppEvents.fireOnBlockBroken(block);
                }
            }
        });
        system.afterEvents.scriptEventReceive.subscribe((event) => {
            const id = event.id;
            if (id === 'razz_sup:falling_block_on_land') {
                event.sourceEntity.triggerEvent("razz_sup:clear_on_land");
                this.maybeTurnToBlock(event.sourceEntity);
            }
        });
    }
    fall(block, below) {
        const belowBlock = below ?? block.below();
        const def = this.fallingBlocks.get(block.typeId);
        if (belowBlock &&
            (belowBlock.isAir || def?.canFallThroughSpecial?.(belowBlock))
            && this.hasFallingBlock(block.typeId)) {
            const location = offsetVec(block.bottomCenter(), Direction.Up, 0);
            const fallingBlock = block.dimension.spawnEntity(SuppEntities.FallingBlock, location);
            fallingBlock.setDynamicProperty(this.fallingBlockTag, stateToString(block.permutation));
            fallingBlock.triggerEvent(this.encodeEvent(block));
            fallingBlock.triggerEvent("razz_sup:add_collision"); //cant have on fist tick because idk game will push it out of blocks its not even touching
            const def = this.fallingBlocks.get(block.typeId);
            def?.saveAdditionalToEntity?.(fallingBlock, block);
            block.setType(McBlocks.Air);
            suppEvents.fireOnBlockBroken(block);
            return true;
        }
        return false;
    }
    encodeEvent(block) {
        if (block.typeId == "razz_sup:ash" /* SuppBlocks.Ash */) {
            return "razz_sup:ash_" + block.permutation.getState(SuppStates.LayerCount);
        }
        return block.typeId;
    }
    hasFallingBlock(blockId) {
        return this.fallingBlocks.has(blockId);
    }
    register(blockId, definition) {
        this.fallingBlocks.set(blockId, definition); //or use tag?
    }
    onTick(entity) {
        //this.maybeTurnToBlock(entity);
    }
    maybeTurnToBlock(entity) {
        const blockAt = getBlockSafe(entity.dimension, entity.location);
        if (blockAt && !entity.isFalling && entity) {
            const blockToPlace = stringToState(entity.getDynamicProperty(this.fallingBlockTag));
            const blockId = blockToPlace.type.id;
            const def = this.fallingBlocks.get(blockId);
            let placed = false;
            if (def?.placeEntityOntoSpecial?.(entity, blockAt, blockToPlace)) {
                placed = true;
            }
            else if (isReplaceable(blockAt)) {
                blockAt.setPermutation(blockToPlace);
                suppEvents.fireOnBlockPlaced(blockAt);
                def?.onLand?.(entity, blockAt);
                placed = true;
            }
            if (!placed) {
                entity.dimension.spawnItem(new ItemStack(blockId), entity.location);
            }
            entity.remove();
        }
    }
    shouldTrack(entity) {
        return entity.typeId == SuppEntities.FallingBlock;
    }
}
export const fallingBlocksManager = new FallingBlocksManager();
export const FallingBlockComponent = {
    onPlace(event) {
        const block = event.block;
        fallingBlocksManager.fall(block);
    }
};
