import { describe, it, expect } from 'vitest';
import { findPathAStar } from '../world/pathfinding';
import { type World } from '../../core/types';
import { TileType } from '../../core/terrain';

describe('Pathfinding', () => {
    const createTestWorld = (width: number, height: number, tileType: number = TileType.EMPTY): World => ({
        width,
        height,
        tiles: new Array(width * height).fill(tileType),
        actors: new Map(),
        exit: { x: 0, y: 0 }
    });

    it('should find a path between two reachable points', () => {
        const world = createTestWorld(10, 10);
        const seen = new Uint8Array(100).fill(1);
        
        const path = findPathAStar(world, seen, { x: 0, y: 0 }, { x: 0, y: 3 });
        
        expect(path.length).toBe(4); // 0,0 -> 0,1 -> 0,2 -> 0,3
        expect(path[0]).toEqual({ x: 0, y: 0 });
        expect(path[3]).toEqual({ x: 0, y: 3 });
    });

    it('should return empty array if target is a wall', () => {
        const world = createTestWorld(10, 10);
        world.tiles[30] = TileType.WALL; // Wall at 0,3
        const seen = new Uint8Array(100).fill(1);
        
        const path = findPathAStar(world, seen, { x: 0, y: 0 }, { x: 0, y: 3 });
        
        expect(path).toEqual([]);
    });

    it('should return empty array if no path exists', () => {
        const world = createTestWorld(10, 10);
        // Create a wall blockage
        for(let x=0; x<10; x++) world.tiles[10 + x] = TileType.WALL;
        
        const seen = new Uint8Array(100).fill(1);
        
        const path = findPathAStar(world, seen, { x: 0, y: 0 }, { x: 0, y: 5 });
        
        expect(path).toEqual([]);
    });

    it('should respect ignoreBlockedTarget option', () => {
        const world = createTestWorld(10, 10);
        // Place an actor at target
        world.actors.set(1, { id: 1, pos: { x: 0, y: 3 }, type: 'rat', category: 'combatant' } as any);
        
        const seen = new Uint8Array(100).fill(1);
        
        // Without option, it should be blocked (because actor is there)
        // Wait, default pathfinding might treat actors as blocking unless specified. 
        // Let's check `isBlocked` usage in `pathfinding.ts`.
        // It calls `isBlocked` which checks actors.
        
        // However, findPathAStar has logic:
        // if (!options.ignoreBlockedTarget && isBlocked(w, end.x, end.y, options.em)) return [];
        
        const pathBlocked = findPathAStar(world, seen, { x: 0, y: 0 }, { x: 0, y: 3 });
        expect(pathBlocked).toEqual([]);

        const pathIgnored = findPathAStar(world, seen, { x: 0, y: 0 }, { x: 0, y: 3 }, { ignoreBlockedTarget: true });
        expect(pathIgnored.length).toBeGreaterThan(0);
        expect(pathIgnored[pathIgnored.length - 1]).toEqual({ x: 0, y: 3 });
    });

    it('should respect ignoreSeen option', () => {
        const world = createTestWorld(10, 10);
        const seen = new Uint8Array(100).fill(0); // Nothing seen
        
        // Without ignoreSeen, should fail because target/path is unseen
        const pathUnseen = findPathAStar(world, seen, { x: 0, y: 0 }, { x: 0, y: 3 });
        expect(pathUnseen).toEqual([]);
        
        // With ignoreSeen, should succeed
        const pathSeenIgnored = findPathAStar(world, seen, { x: 0, y: 0 }, { x: 0, y: 3 }, { ignoreSeen: true });
        expect(pathSeenIgnored.length).toBe(4);
    });
});
