import type { TilePlacement } from "../../app/lib/types.ts";

export type Direction = NonNullable<TilePlacement["direction"]>;
export const VECTORS: Record<Direction, [number, number]> = {
  north: [0, -1], east: [1, 0], south: [0, 1], west: [-1, 0],
};
export const OPPOSITE: Record<Direction, Direction> = {
  north: "south", east: "west", south: "north", west: "east",
};
export const isBelt = (p: TilePlacement) => !!p.entityId?.endsWith("transport-belt") || !!p.entityId?.endsWith("underground-belt");
export const isPipe = (p: TilePlacement) => p.entityId === "pipe" || p.entityId === "pipe-to-ground";

export function previewGeometry(placements: TilePlacement[]) {
  const tiles = new Map(placements.filter((p) => p.kind !== "link" && p.width === 1 && p.height === 1).map((p) => [`${p.x},${p.y}`, p]));
  const neighbor = (p: TilePlacement, direction: Direction) => {
    const [dx, dy] = VECTORS[direction];
    return tiles.get(`${p.x + dx},${p.y + dy}`);
  };
  const pipePorts = (p: TilePlacement): Direction[] => p.entityId === "pipe-to-ground"
    ? [p.direction ?? "north"] : Object.keys(VECTORS) as Direction[];
  const connections = (p: TilePlacement) => (Object.keys(VECTORS) as Direction[]).filter((direction) => {
    const n = neighbor(p, direction);
    if (!n) return false;
    if (isPipe(p)) return isPipe(n) && pipePorts(p).includes(direction) && pipePorts(n).includes(OPPOSITE[direction]);
    return isBelt(n) && n.beltEnd !== "input" && n.direction === OPPOSITE[direction];
  });
  const tunnels: Array<{ from: TilePlacement; to: TilePlacement }> = [];
  for (const p of tiles.values()) {
    const isUndergroundPipe = p.entityId === "pipe-to-ground";
    if (!isUndergroundPipe && p.beltEnd !== "input") continue;
    const direction = isUndergroundPipe ? OPPOSITE[p.direction ?? "north"] : p.direction ?? "north";
    const [dx, dy] = VECTORS[direction];
    for (let distance = 1; distance <= 11; distance++) {
      const n = tiles.get(`${p.x + dx * distance},${p.y + dy * distance}`);
      if (!n || n.entityId !== p.entityId) continue;
      if (isUndergroundPipe ? n.direction === direction : n.direction === p.direction && n.beltEnd === "output") {
        if (!isUndergroundPipe || p.x < n.x || p.y < n.y) tunnels.push({ from: p, to: n });
        break;
      }
    }
  }
  const poles = placements.filter((p) => p.entityId === "substation");
  const power = poles.flatMap((p) => ["east", "south"].flatMap((direction) => {
    const matches = poles.filter((n) => direction === "east"
      ? n.y === p.y && n.x > p.x && n.x - p.x <= 28
      : n.x === p.x && n.y > p.y && n.y - p.y <= 28);
    matches.sort((a, b) => (a.x - p.x) + (a.y - p.y) - (b.x - p.x) - (b.y - p.y));
    return matches[0] ? [{ from: p, to: matches[0] }] : [];
  }));
  return { connections, tunnels, power };
}

/** Integer world coordinates are also SVG coordinates: no half-tile offset. */
export function previewBounds(bounds: { minX: number; minY: number; maxX: number; maxY: number }) {
  const x = Math.floor(bounds.minX) - 1;
  const y = Math.floor(bounds.minY) - 1;
  return { x, y, width: Math.ceil(bounds.maxX) + 1 - x, height: Math.ceil(bounds.maxY) + 1 - y };
}
