import { BlockPermutation, EntityInventoryComponent, system, world } from "@minecraft/server";
import * as utils from './serverUtils';
import { expansionEvents } from "./serverExpansion";
class BlockEntityManager {
    registerBlockEntity(typeId, blockEntity) {
        this.blockEntityMap.set(typeId, blockEntity);
    }
    /**
    * @remarks
    * 获取方块实体，若该方块不为方块实体则返回undefined
    */
    getBlockEntity(dimension, location) {
        const entities = dimension.getEntitiesAtBlockLocation(location);
        const block = dimension.getBlock(location);
        for (const entity of entities) {
            if (block && entity.typeId == block.typeId && this.blockEntityMap.has(entity.typeId)) {
                const data = {
                    typeId: entity.typeId,
                    block,
                    entity,
                    location,
                    dimension,
                    staticData: this.blockEntityMap.get(entity.typeId)?.staticData
                };
                return data;
            }
        }
        return undefined;
    }
    /**
    * @remarks
    * 移除方块实体
    */
    removeBlockEntity(blockEntity, opt) {
        if (opt?.blockLoot) {
            const blockItem = blockEntity.block.getItemStack(1, true);
            if (blockItem) {
                blockEntity.dimension.spawnItem(blockItem, blockEntity.location);
            }
        }
        if (opt?.entityLoot) {
            const dimension = blockEntity.dimension;
            const container = blockEntity.entity.getComponent(EntityInventoryComponent.componentId)?.container;
            if (container) {
                for (let i = 0, length = container.size; i < length; i++) {
                    const itemStack = container.getItem(i);
                    if (itemStack) {
                        dimension.spawnItem(itemStack, blockEntity.location);
                    }
                }
            }
        }
        blockEntity.entity.remove();
        blockEntity.block.setPermutation(BlockPermutation.resolve('minecraft:air'));
    }
    //负责初始化, tick, 位置绑定和销毁
    blockEntityTick() {
        world.afterEvents.dataDrivenEntityTrigger.subscribe(({ entity }) => {
            if (!entity.isValid())
                return;
            const baseLoc = entity.getDynamicProperty('block_entity:base_loc');
            const baseRot = entity.getDynamicProperty('block_entity:base_rot');
            if (!baseLoc || !baseRot) {
                entity.setDynamicProperty('block_entity:base_loc', entity.location);
                entity.setDynamicProperty('block_entity:base_rot', { x: entity.getRotation().x, y: entity.getRotation().y, z: 0 });
                return;
            }
            if (!utils.vector.equals(baseLoc, entity.location)) {
                const baseRot = entity.getDynamicProperty('block_entity:base_rot');
                entity.teleport(baseLoc, { rotation: { x: baseRot.x, y: baseRot.y } });
            }
            else {
                const data = this.getBlockEntity(entity.dimension, entity.location);
                if (!data) {
                    const onRemove = this.blockEntityMap.get(entity.typeId)?.onRemove;
                    if (onRemove)
                        onRemove({ entity });
                    entity.remove();
                }
                else {
                    const onTick = this.blockEntityMap.get(entity.typeId)?.onTick;
                    if (onTick)
                        onTick({ blockEntity: data });
                }
            }
        }, { eventTypes: ['block_entity:tick'] });
    }
    //负责玩家看向方块实体事件
    raycastBlock() {
        expansionEvents.playerLookAtBlock.subscribe(({ raycastHit, player }) => {
            const block = raycastHit.block;
            if (!this.blockEntityMap.has(block.typeId))
                return;
            const blockEntity = this.getBlockEntity(block.dimension, block);
            if (!blockEntity)
                return;
            const onPlayerLook = this.blockEntityMap.get(block.typeId)?.onPlayerLook;
            if (onPlayerLook)
                onPlayerLook({ blockEntity, player, blockFace: raycastHit.face, faceLocation: raycastHit.faceLocation });
        }, { maxDistance: 16 });
    }
    constructor() {
        this.blockEntityMap = new Map();
        this.blockEntityTick();
        this.raycastBlock();
        world.beforeEvents.worldInitialize.subscribe(({ blockComponentRegistry }) => {
            this.blockEntityMap.forEach((blockEntityComp, typeId) => {
                const blockComp = {
                    onPlayerInteract({ block, player, face, faceLocation }) {
                        const data = blockEntityMng.getBlockEntity(block.dimension, block.location);
                        player = player;
                        faceLocation = faceLocation;
                        const itemStack = utils.item.getEquipment(player);
                        if (data) {
                            const onPlayerInteract = blockEntityComp.onPlayerInteract;
                            if (onPlayerInteract)
                                onPlayerInteract({ blockEntity: data, itemStack, player, blockFace: face, faceLocation });
                        }
                    },
                    beforeOnPlayerPlace({ block, dimension, player, permutationToPlace }) {
                        if (typeId != permutationToPlace.type.id)
                            return;
                        player = player;
                        const item = utils.item.getEquipment(player);
                        const onPlayerPlace = blockEntityComp.onPlayerPlace;
                        if (onPlayerPlace)
                            onPlayerPlace({ block, dimension, player, permutationToPlace, blockItem: item });
                        system.run(() => {
                            player = player;
                            dimension.spawnEntity(block.typeId, block.bottomCenter());
                            const data = blockEntityMng.getBlockEntity(dimension, block);
                            if (!data)
                                return;
                            const blockEntityInit = blockEntityComp.init;
                            if (blockEntityInit)
                                blockEntityInit({ blockEntity: data, player, blockItem: item });
                        });
                    }
                };
                blockComponentRegistry.registerCustomComponent(typeId, blockComp);
            });
        });
    }
}
export const blockEntityMng = new BlockEntityManager();
