import { describe, it, expect } from 'vitest';
import { generateWorld } from '../world/generator';
import { isWall, inBounds } from '../world/world-logic';

describe('World Generator', () => {
  describe('generateWorld', () => {
    it('should generate a world with correct dimensions', () => {
      const runState = {
        stats: { maxHp: 20, hp: 20, attack: 5, defense: 2 },
        inventory: { gold: 0, items: [] }
      };
      
      const { world } = generateWorld(1, runState);
      
      expect(world.width).toBe(60);
      expect(world.height).toBe(40);
      expect(world.tiles.length).toBe(60 * 40);
    });

    it('should place player actor', () => {
      const runState = {
        stats: { maxHp: 20, hp: 20, attack: 5, defense: 2 },
        inventory: { gold: 0, items: [] }
      };
      
      const { world, playerId } = generateWorld(1, runState);
      
      expect(playerId).toBe(1);
      const player = world.actors.get(playerId);
      expect(player).toBeDefined();
      expect(player?.isPlayer).toBe(true);
      expect(player?.stats).toEqual(runState.stats);
    });

    it('should create walkable rooms', () => {
      const runState = {
        stats: { maxHp: 20, hp: 20, attack: 5, defense: 2 },
        inventory: { gold: 0, items: [] }
      };
      
      const { world, playerId } = generateWorld(1, runState);
      const player = world.actors.get(playerId)!;
      
      // Player should spawn in a walkable area
      expect(isWall(world, player.pos.x, player.pos.y)).toBe(false);
    });

    it('should place exit in valid location', () => {
      const runState = {
        stats: { maxHp: 20, hp: 20, attack: 5, defense: 2 },
        inventory: { gold: 0, items: [] }
      };
      
      const { world } = generateWorld(1, runState);
      
      expect(inBounds(world, world.exit.x, world.exit.y)).toBe(true);
      // Exit should be on a floor tile
      expect(isWall(world, world.exit.x, world.exit.y)).toBe(false);
    });

    it('should create enemies', () => {
      const runState = {
        stats: { maxHp: 20, hp: 20, attack: 5, defense: 2 },
        inventory: { gold: 0, items: [] }
      };
      
      const { world } = generateWorld(1, runState);
      
      // Should have player + enemies
      expect(world.actors.size).toBeGreaterThan(1);
      
      // All non-player actors should be enemies
      const enemies = Array.from(world.actors.values()).filter(a => !a.isPlayer);
      expect(enemies.length).toBeGreaterThan(0);
      
      // Enemies should have stats
      enemies.forEach(enemy => {
        expect(enemy.stats).toBeDefined();
        expect(enemy.stats!.hp).toBeGreaterThan(0);
        expect(enemy.stats!.attack).toBeGreaterThan(0);
      });
    });

    it('should generate deterministic maps for same level', () => {
      const runState = {
        stats: { maxHp: 20, hp: 20, attack: 5, defense: 2 },
        inventory: { gold: 0, items: [] }
      };
      
      const { world: world1, playerId: player1 } = generateWorld(1, runState);
      const { world: world2, playerId: player2 } = generateWorld(1, runState);
      
      // Same level should generate identical layouts
      expect(world1.tiles).toEqual(world2.tiles);
      expect(world1.exit).toEqual(world2.exit);
      
      const player1Pos = world1.actors.get(player1)!.pos;
      const player2Pos = world2.actors.get(player2)!.pos;
      expect(player1Pos).toEqual(player2Pos);
    });

    it('should generate different maps for different levels', () => {
      const runState = {
        stats: { maxHp: 20, hp: 20, attack: 5, defense: 2 },
        inventory: { gold: 0, items: [] }
      };
      
      const { world: world1 } = generateWorld(1, runState);
      const { world: world2 } = generateWorld(2, runState);
      
      // Different levels should have different layouts
      expect(world1.tiles).not.toEqual(world2.tiles);
    });

    it('should scale enemy difficulty with level', () => {
      const runState = {
        stats: { maxHp: 20, hp: 20, attack: 5, defense: 2 },
        inventory: { gold: 0, items: [] }
      };
      
      const { world: world1 } = generateWorld(1, runState);
      const { world: world5 } = generateWorld(5, runState);
      
      const enemies1 = Array.from(world1.actors.values()).filter(a => !a.isPlayer);
      const enemies5 = Array.from(world5.actors.values()).filter(a => !a.isPlayer);
      
      // Higher level should have more enemies
      expect(enemies5.length).toBeGreaterThan(enemies1.length);
      
      // Higher level enemies should have higher stats
      const avgHp1 = enemies1.reduce((sum, e) => sum + (e.stats?.hp || 0), 0) / enemies1.length;
      const avgHp5 = enemies5.reduce((sum, e) => sum + (e.stats?.hp || 0), 0) / enemies5.length;
      expect(avgHp5).toBeGreaterThan(avgHp1);
    });
  });
});
