import { describe, it, expect } from 'vitest';
import { applyAction, decideEnemyAction } from '../simulation/simulation';
import { type World, type Actor, type EntityId, type CombatantActor } from '../../core/types';
import { EntityManager } from '../EntityManager';

describe('Combat Simulation', () => {
  let entityManager: EntityManager;

  const createTestWorld = (actors: Map<EntityId, Actor>): World => {
    return {
        width: 10,
        height: 10,
        tiles: new Array(100).fill(0),
        actors,
        exit: { x: 9, y: 9 }
    };
  };
  
  const createTestStats = (overrides: Partial<any> = {}) => ({
    maxHp: 20, hp: 20, attack: 5, defense: 2, level: 1, exp: 0, expToNextLevel: 10,
    statPoints: 0, skillPoints: 0, strength: 10, dexterity: 10, intelligence: 10, passiveNodes: [],
    critChance: 0, critMultiplier: 100, accuracy: 100, lifesteal: 0, evasion: 0, blockChance: 0, luck: 0,
    ...overrides
  });

  describe('applyAction - success paths', () => {
    it('should deal damage when player attacks enemy', () => {
      const actors = new Map<EntityId, Actor>();
      actors.set(1, {
        id: 1, category: "combatant", isPlayer: true, type: "player", pos: { x: 3, y: 3 }, speed: 100, stats: createTestStats()
      } as any);
      actors.set(2, {
        id: 2, category: "combatant", isPlayer: false, type: "rat", pos: { x: 4, y: 3 }, speed: 100, stats: createTestStats({ maxHp: 10, hp: 10, attack: 3, defense: 1 })
      } as any);

      const world = createTestWorld(actors);
      entityManager = new EntityManager(world);
      const events = applyAction(world, 1, { type: "attack", targetId: 2 }, entityManager);

      const enemy = world.actors.get(2) as CombatantActor;
      expect(enemy.stats.hp).toBeLessThan(10);
      expect(events.some(e => e.type === "attacked")).toBe(true);
    });

    it("should kill enemy and spawn EXP orb without ID reuse collision", () => {
      const actors = new Map<EntityId, Actor>();
      actors.set(1, {
        id: 1, category: "combatant", isPlayer: true, type: "player", pos: { x: 3, y: 3 }, speed: 100, stats: createTestStats({ attack: 50 })
      } as any);
      actors.set(2, {
        id: 2, category: "combatant", isPlayer: false, type: "rat", pos: { x: 4, y: 3 }, speed: 100, stats: createTestStats({ maxHp: 10, hp: 10, attack: 3, defense: 1 })
      } as any);

      const world = createTestWorld(actors);
      entityManager = new EntityManager(world);
      applyAction(world, 1, { type: "attack", targetId: 2 }, entityManager);

      // Enemy (id 2) should be gone
      expect(world.actors.has(2)).toBe(false);
      
      // A new ID should be generated for the orb (should be 3)
      const orb = [...world.actors.values()].find(a => a.type === "exp_orb");
      expect(orb).toBeDefined();
      expect(orb!.id).toBe(3);
    });

    it("should destruction tile when walking on destructible-by-walk tile", () => {
      const actors = new Map<EntityId, Actor>();
      actors.set(1, {
        id: 1, category: "combatant", isPlayer: true, type: "player", pos: { x: 3, y: 3 }, speed: 100, stats: createTestStats()
      } as any);

      const world = createTestWorld(actors);
      // tile at 4,3 is grass (15) which is destructible by walk
      const grassIdx = 3 * 10 + 4;
      world.tiles[grassIdx] = 15; // TileType.GRASS

      entityManager = new EntityManager(world);
      applyAction(world, 1, { type: "move", dx: 1, dy: 0 }, entityManager);

      // Player moved to 4,3
      const player = world.actors.get(1);
      expect(player!.pos).toEqual({ x: 4, y: 3 });

      // Tile should effectively be destroyed (turned to saplings/2)
      expect(world.tiles[grassIdx]).toBe(2); // TileType.GRASS_SAPLINGS
    });
  });

  describe("decideEnemyAction - AI Logic", () => {
      it("should path around walls", () => {
          const actors = new Map<EntityId, Actor>();
          const player = { id: 1, category: "combatant", isPlayer: true, pos: { x: 5, y: 3 }, stats: createTestStats() } as any;
          const enemy = { id: 2, category: "combatant", isPlayer: false, pos: { x: 3, y: 3 }, stats: createTestStats() } as any;
          actors.set(1, player);
          actors.set(2, enemy);

          const world = createTestWorld(actors);
          world.tiles[3 * 10 + 4] = 4; // Wall

          entityManager = new EntityManager(world);
          const decision = decideEnemyAction(world, enemy, player, entityManager);
          
          expect(decision.action.type).toBe("move");
      });

      it("should attack if player is adjacent", () => {
          const actors = new Map<EntityId, Actor>();
          const player = { id: 1, category: "combatant", isPlayer: true, pos: { x: 4, y: 3 }, stats: createTestStats() } as any;
          const enemy = { 
            id: 2, 
            category: "combatant", 
            isPlayer: false, 
            pos: { x: 3, y: 3 }, 
            stats: createTestStats(),
            // Set AI state to pursuing so the enemy will attack when adjacent
            aiState: "pursuing",
            lastKnownPlayerPos: { x: 4, y: 3 }
          } as any;
          actors.set(1, player);
          actors.set(2, enemy);

          const world = createTestWorld(actors);
          entityManager = new EntityManager(world);
          
          const decision = decideEnemyAction(world, enemy, player, entityManager);
          expect(decision.action).toEqual({ type: "attack", targetId: 1 });
      });
  });
});
