import type { World, Vec2 } from "../../core/types";
import { inBounds, isWall, isBlocked, idx } from "./world-logic";
import { type EntityManager } from "../EntityManager";
import * as ROT from "rot-js";

/**
 * 4-dir A* pathfinding using rot-js.
 * Returns an array of positions INCLUDING start and end. If no path, returns [].
 *
 * Exploration rule:
 * - You cannot path THROUGH unseen tiles.
 * - You cannot path TO an unseen target tile.
 */
export function findPathAStar(
  w: World, 
  seen: Uint8Array, 
  start: Vec2, 
  end: Vec2, 
  options: { ignoreBlockedTarget?: boolean; ignoreSeen?: boolean; em?: EntityManager } = {}
): Vec2[] {
  // Validate target
  if (!inBounds(w, end.x, end.y)) return [];
  if (isWall(w, end.x, end.y)) return [];
  
  // Check if target is blocked (unless ignoring)
  if (!options.ignoreBlockedTarget && isBlocked(w, end.x, end.y, options.em)) return [];
  
  // Check if target is unseen (unless ignoring)
  if (!options.ignoreSeen && seen[idx(w, end.x, end.y)] !== 1) return [];

  // Create passable callback for rot-js
  const passableCallback = (x: number, y: number): boolean => {
    // Out of bounds or wall = not passable
    if (!inBounds(w, x, y)) return false;
    if (isWall(w, x, y)) return false;

    // Start position is always passable
    if (x === start.x && y === start.y) return true;
    
    // Target position is passable (we already validated it above)
    if (x === end.x && y === end.y) return true;

    // Check seen requirement
    if (!options.ignoreSeen && seen[idx(w, x, y)] !== 1) return false;

    // Check actor blocking
    if (isBlocked(w, x, y, options.em)) return false;

    return true;
  };

  // Use rot-js A* pathfinding with 4-directional topology
  const astar = new ROT.Path.AStar(end.x, end.y, passableCallback, { topology: 4 });

  const path: Vec2[] = [];
  
  // Compute path from start to end
  astar.compute(start.x, start.y, (x: number, y: number) => {
    path.push({ x, y });
  });

  return path;
}
