/**
 * TilemapPhysicsSystem
 * Tilemap 物理系统
 *
 * 负责将 TilemapComponent 的碰撞数据同步到物理世界。
 * 需要与 Physics2DSystem 配合使用。
 */

import { EntitySystem, Matcher, ECSSystem, type Entity, type Scene } from '@esengine/ecs-framework';
import { TransformComponent } from '@esengine/ecs-components';
import { TilemapComponent } from '../TilemapComponent';
import { TilemapCollider2DComponent, type CollisionRect } from './TilemapCollider2DComponent';

/**
 * 物理世界接口（避免直接依赖 physics-rapier2d）
 */
export interface IPhysicsWorld {
    createStaticCollider(
        entityId: number,
        position: { x: number; y: number },
        halfExtents: { x: number; y: number },
        collisionLayer: number,
        collisionMask: number,
        friction: number,
        restitution: number,
        isTrigger: boolean
    ): number | null;
    removeCollider(handle: number): void;
}

/**
 * 物理系统接口
 */
export interface IPhysics2DSystem {
    world: IPhysicsWorld;
}

/**
 * Tilemap 物理系统
 *
 * 监听带有 TilemapComponent 和 TilemapCollider2DComponent 的实体，
 * 自动将碰撞数据转换为物理碰撞体。
 */
@ECSSystem('TilemapPhysics', { updateOrder: 50 })
export class TilemapPhysicsSystem extends EntitySystem {
    private _physicsWorld: IPhysicsWorld | null = null;
    private _pendingEntities: Entity[] = [];

    constructor() {
        super(Matcher.empty().all(TilemapComponent, TilemapCollider2DComponent));
    }

    /**
     * 设置物理世界引用
     */
    public setPhysicsWorld(world: IPhysicsWorld): void {
        this._physicsWorld = world;

        // 处理待处理的实体
        for (const entity of this._pendingEntities) {
            this._createColliders(entity);
        }
        this._pendingEntities = [];
    }

    protected override onAdded(entity: Entity): void {
        if (!this._physicsWorld) {
            this._pendingEntities.push(entity);
            return;
        }
        this._createColliders(entity);
    }

    protected override onRemoved(entity: Entity): void {
        this._removeColliders(entity);

        const idx = this._pendingEntities.indexOf(entity);
        if (idx >= 0) {
            this._pendingEntities.splice(idx, 1);
        }
    }

    protected override process(entities: readonly Entity[]): void {
        if (!this._physicsWorld) return;

        for (const entity of entities) {
            const tilemap = entity.getComponent(TilemapComponent);
            const collider = entity.getComponent(TilemapCollider2DComponent);

            if (!tilemap || !collider) continue;

            // 检查碰撞数据是否变化
            const currentVersion = tilemap.renderDirty ? Date.now() : collider._lastCollisionVersion;
            if (collider._needsRebuild || currentVersion !== collider._lastCollisionVersion) {
                this._rebuildColliders(entity);
                collider._lastCollisionVersion = currentVersion;
            }
        }
    }

    /**
     * 创建碰撞体
     */
    private _createColliders(entity: Entity): void {
        const tilemap = entity.getComponent(TilemapComponent);
        const collider = entity.getComponent(TilemapCollider2DComponent);
        const transform = entity.getComponent(TransformComponent);

        if (!tilemap || !collider || !this._physicsWorld) return;

        // 生成碰撞矩形
        const collisionData = tilemap.collisionData;
        collider.generateCollisionRects(
            collisionData,
            tilemap.width,
            tilemap.height,
            tilemap.tileWidth,
            tilemap.tileHeight
        );

        // 获取实体位置偏移
        const offsetX = transform?.position.x ?? 0;
        const offsetY = transform?.position.y ?? 0;

        // 计算地图总高度（像素），用于 Y 轴翻转
        // Calculate total map height (pixels) for Y-axis flip
        const mapPixelHeight = tilemap.height * tilemap.tileHeight;

        // 为每个碰撞矩形创建物理碰撞体
        for (const rect of collider._collisionRects) {
            // Y 轴翻转：rect.y 是从顶部计算的，需要翻转到底部
            // Y-axis flip: rect.y is calculated from top, needs flip to bottom
            const flippedY = mapPixelHeight - rect.y - rect.height;

            const handle = this._physicsWorld.createStaticCollider(
                entity.id,
                {
                    x: offsetX + rect.x + rect.width / 2,
                    y: offsetY + flippedY + rect.height / 2,
                },
                {
                    x: rect.width / 2,
                    y: rect.height / 2,
                },
                collider.collisionLayer,
                collider.collisionMask,
                collider.friction,
                collider.restitution,
                collider.isTrigger
            );

            if (handle !== null) {
                collider._colliderHandles.push(handle);
            }
        }

        collider._needsRebuild = false;
        this.logger.debug(`Created ${collider._colliderHandles.length} colliders for tilemap entity ${entity.name}`);
    }

    /**
     * 移除碰撞体
     */
    private _removeColliders(entity: Entity): void {
        const collider = entity.getComponent(TilemapCollider2DComponent);
        if (!collider || !this._physicsWorld) return;

        for (const handle of collider._colliderHandles) {
            this._physicsWorld.removeCollider(handle);
        }
        collider._colliderHandles = [];
    }

    /**
     * 重建碰撞体
     */
    private _rebuildColliders(entity: Entity): void {
        this._removeColliders(entity);
        this._createColliders(entity);
    }

    protected override onDestroy(): void {
        this._physicsWorld = null;
        this._pendingEntities = [];
    }
}
