import { ComponentSparseSet } from '../../../src/ECS/Utils/ComponentSparseSet';
import { Entity } from '../../../src/ECS/Entity';
import { Component } from '../../../src/ECS/Component';
import { Scene } from '../../../src/ECS/Scene';

// 测试组件类
class PositionComponent extends Component {
    constructor(public x: number = 0, public y: number = 0) {
        super();
    }
}

class VelocityComponent extends Component {
    constructor(public dx: number = 0, public dy: number = 0) {
        super();
    }
}

class HealthComponent extends Component {
    constructor(public health: number = 100, public maxHealth: number = 100) {
        super();
    }
}

class RenderComponent extends Component {
    constructor(public visible: boolean = true) {
        super();
    }
}

describe('ComponentSparseSet', () => {
    let componentSparseSet: ComponentSparseSet;
    let entity1: Entity;
    let entity2: Entity;
    let entity3: Entity;
    let scene: Scene;

    beforeEach(() => {
        componentSparseSet = new ComponentSparseSet();
        scene = new Scene();

        entity1 = scene.createEntity('entity1');
        entity1.addComponent(new PositionComponent(10, 20));
        entity1.addComponent(new VelocityComponent(1, 2));

        entity2 = scene.createEntity('entity2');
        entity2.addComponent(new PositionComponent(30, 40));
        entity2.addComponent(new HealthComponent(80, 100));

        entity3 = scene.createEntity('entity3');
        entity3.addComponent(new VelocityComponent(3, 4));
        entity3.addComponent(new HealthComponent(50, 100));
        entity3.addComponent(new RenderComponent(true));
    });

    describe('基本实体操作', () => {
        it('应该能添加实体', () => {
            componentSparseSet.addEntity(entity1);
            
            expect(componentSparseSet.size).toBe(1);
            expect(componentSparseSet.getAllEntities()).toContain(entity1);
        });

        it('应该能移除实体', () => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
            
            componentSparseSet.removeEntity(entity1);
            
            expect(componentSparseSet.size).toBe(1);
            expect(componentSparseSet.getAllEntities()).not.toContain(entity1);
            expect(componentSparseSet.getAllEntities()).toContain(entity2);
        });

        it('应该处理重复添加实体', () => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity1);
            
            expect(componentSparseSet.size).toBe(1);
        });

        it('应该处理移除不存在的实体', () => {
            componentSparseSet.removeEntity(entity1);
            
            expect(componentSparseSet.size).toBe(0);
        });
    });

    describe('单组件查询', () => {
        beforeEach(() => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
            componentSparseSet.addEntity(entity3);
        });

        it('应该能查询Position组件', () => {
            const entities = componentSparseSet.queryByComponent(PositionComponent);
            
            expect(entities.size).toBe(2);
            expect(entities.has(entity1)).toBe(true);
            expect(entities.has(entity2)).toBe(true);
            expect(entities.has(entity3)).toBe(false);
        });

        it('应该能查询Velocity组件', () => {
            const entities = componentSparseSet.queryByComponent(VelocityComponent);
            
            expect(entities.size).toBe(2);
            expect(entities.has(entity1)).toBe(true);
            expect(entities.has(entity2)).toBe(false);
            expect(entities.has(entity3)).toBe(true);
        });

        it('应该能查询Health组件', () => {
            const entities = componentSparseSet.queryByComponent(HealthComponent);
            
            expect(entities.size).toBe(2);
            expect(entities.has(entity1)).toBe(false);
            expect(entities.has(entity2)).toBe(true);
            expect(entities.has(entity3)).toBe(true);
        });

        it('应该能查询Render组件', () => {
            const entities = componentSparseSet.queryByComponent(RenderComponent);
            
            expect(entities.size).toBe(1);
            expect(entities.has(entity3)).toBe(true);
        });
    });

    describe('多组件AND查询', () => {
        beforeEach(() => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
            componentSparseSet.addEntity(entity3);
        });

        it('应该能查询Position+Velocity组件', () => {
            const entities = componentSparseSet.queryMultipleAnd([PositionComponent, VelocityComponent]);
            
            expect(entities.size).toBe(1);
            expect(entities.has(entity1)).toBe(true);
        });

        it('应该能查询Position+Health组件', () => {
            const entities = componentSparseSet.queryMultipleAnd([PositionComponent, HealthComponent]);
            
            expect(entities.size).toBe(1);
            expect(entities.has(entity2)).toBe(true);
        });

        it('应该能查询Velocity+Health组件', () => {
            const entities = componentSparseSet.queryMultipleAnd([VelocityComponent, HealthComponent]);
            
            expect(entities.size).toBe(1);
            expect(entities.has(entity3)).toBe(true);
        });

        it('应该能查询三个组件', () => {
            const entities = componentSparseSet.queryMultipleAnd([
                VelocityComponent, 
                HealthComponent, 
                RenderComponent
            ]);
            
            expect(entities.size).toBe(1);
            expect(entities.has(entity3)).toBe(true);
        });

        it('应该处理不存在的组合', () => {
            const entities = componentSparseSet.queryMultipleAnd([
                PositionComponent, 
                VelocityComponent, 
                HealthComponent, 
                RenderComponent
            ]);
            
            expect(entities.size).toBe(0);
        });
    });

    describe('多组件OR查询', () => {
        beforeEach(() => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
            componentSparseSet.addEntity(entity3);
        });

        it('应该能查询Position或Velocity组件', () => {
            const entities = componentSparseSet.queryMultipleOr([PositionComponent, VelocityComponent]);
            
            expect(entities.size).toBe(3);
            expect(entities.has(entity1)).toBe(true);
            expect(entities.has(entity2)).toBe(true);
            expect(entities.has(entity3)).toBe(true);
        });

        it('应该能查询Health或Render组件', () => {
            const entities = componentSparseSet.queryMultipleOr([HealthComponent, RenderComponent]);
            
            expect(entities.size).toBe(2);
            expect(entities.has(entity1)).toBe(false);
            expect(entities.has(entity2)).toBe(true);
            expect(entities.has(entity3)).toBe(true);
        });

        it('应该处理单个组件的OR查询', () => {
            const entities = componentSparseSet.queryMultipleOr([RenderComponent]);
            
            expect(entities.size).toBe(1);
            expect(entities.has(entity3)).toBe(true);
        });
    });

    describe('组件检查', () => {
        beforeEach(() => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
        });

        it('应该能检查实体是否有组件', () => {
            expect(componentSparseSet.hasComponent(entity1, PositionComponent)).toBe(true);
            expect(componentSparseSet.hasComponent(entity1, VelocityComponent)).toBe(true);
            expect(componentSparseSet.hasComponent(entity1, HealthComponent)).toBe(false);
            
            expect(componentSparseSet.hasComponent(entity2, PositionComponent)).toBe(true);
            expect(componentSparseSet.hasComponent(entity2, HealthComponent)).toBe(true);
            expect(componentSparseSet.hasComponent(entity2, VelocityComponent)).toBe(false);
        });

        it('应该处理不存在的实体', () => {
            expect(componentSparseSet.hasComponent(entity3, PositionComponent)).toBe(false);
        });
    });

    describe('位掩码操作', () => {
        beforeEach(() => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
        });

        it('应该能获取实体的组件位掩码', () => {
            const mask1 = componentSparseSet.getEntityMask(entity1);
            const mask2 = componentSparseSet.getEntityMask(entity2);
            
            expect(mask1).toBeDefined();
            expect(mask2).toBeDefined();
            expect(mask1).not.toEqual(mask2);
        });

        it('应该处理不存在的实体', () => {
            const mask = componentSparseSet.getEntityMask(entity3);
            expect(mask).toBeUndefined();
        });
    });

    describe('遍历操作', () => {
        beforeEach(() => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
        });

        it('应该能遍历所有实体', () => {
            const entities: Entity[] = [];
            const masks: any[] = [];
            const indices: number[] = [];
            
            componentSparseSet.forEach((entity, mask, index) => {
                entities.push(entity);
                masks.push(mask);
                indices.push(index);
            });
            
            expect(entities.length).toBe(2);
            expect(masks.length).toBe(2);
            expect(indices).toEqual([0, 1]);
            expect(entities).toContain(entity1);
            expect(entities).toContain(entity2);
        });
    });

    describe('工具方法', () => {
        it('应该能检查空状态', () => {
            expect(componentSparseSet.isEmpty).toBe(true);
            
            componentSparseSet.addEntity(entity1);
            expect(componentSparseSet.isEmpty).toBe(false);
        });

        it('应该能清空数据', () => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
            
            componentSparseSet.clear();
            
            expect(componentSparseSet.size).toBe(0);
            expect(componentSparseSet.isEmpty).toBe(true);
        });

        it('应该提供内存统计', () => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
            
            const stats = componentSparseSet.getMemoryStats();
            
            expect(stats.entitiesMemory).toBeGreaterThan(0);
            expect(stats.masksMemory).toBeGreaterThan(0);
            expect(stats.mappingsMemory).toBeGreaterThan(0);
            expect(stats.totalMemory).toBe(
                stats.entitiesMemory + stats.masksMemory + stats.mappingsMemory
            );
        });

        it('应该能验证数据结构完整性', () => {
            componentSparseSet.addEntity(entity1);
            componentSparseSet.addEntity(entity2);
            componentSparseSet.removeEntity(entity1);
            
            expect(componentSparseSet.validate()).toBe(true);
        });
    });

    describe('边界情况', () => {
        it('应该处理空查询', () => {
            componentSparseSet.addEntity(entity1);
            
            const andResult = componentSparseSet.queryMultipleAnd([]);
            const orResult = componentSparseSet.queryMultipleOr([]);
            
            expect(andResult.size).toBe(0);
            expect(orResult.size).toBe(0);
        });

        it('应该处理未注册的组件类型', () => {
            class UnknownComponent extends Component {}
            
            componentSparseSet.addEntity(entity1);
            
            const entities = componentSparseSet.queryByComponent(UnknownComponent);
            expect(entities.size).toBe(0);
        });

        it('应该正确处理实体组件变化', () => {
            // 添加实体
            componentSparseSet.addEntity(entity1);
            expect(componentSparseSet.hasComponent(entity1, PositionComponent)).toBe(true);
            
            // 移除组件后重新添加实体
            entity1.removeComponentByType(PositionComponent);
            componentSparseSet.addEntity(entity1);
            
            expect(componentSparseSet.hasComponent(entity1, PositionComponent)).toBe(false);
            expect(componentSparseSet.hasComponent(entity1, VelocityComponent)).toBe(true);
        });
    });

    describe('性能测试', () => {
        it('应该处理大量实体操作', () => {
            const entities: Entity[] = [];
            
            // 创建大量实体
            for (let i = 0; i < 1000; i++) {
                const entity = scene.createEntity(`entity${i}`);
                entity.addComponent(new PositionComponent(i, i));

                if (i % 2 === 0) {
                    entity.addComponent(new VelocityComponent(1, 1));
                }
                if (i % 3 === 0) {
                    entity.addComponent(new HealthComponent(100, 100));
                }

                entities.push(entity);
                componentSparseSet.addEntity(entity);
            }
            
            expect(componentSparseSet.size).toBe(1000);
            
            // 查询性能测试
            const positionEntities = componentSparseSet.queryByComponent(PositionComponent);
            expect(positionEntities.size).toBe(1000);
            
            const velocityEntities = componentSparseSet.queryByComponent(VelocityComponent);
            expect(velocityEntities.size).toBe(500);
            
            const healthEntities = componentSparseSet.queryByComponent(HealthComponent);
            expect(healthEntities.size).toBeGreaterThan(300);
            
            // AND查询
            const posVelEntities = componentSparseSet.queryMultipleAnd([PositionComponent, VelocityComponent]);
            expect(posVelEntities.size).toBe(500);
        });
    });
});