import { CORRIDOR_CENTER, ENTRANCE, OFFICE, ZONES } from "./constants";
import type { AgentZone, Point } from "./types";

export const WALK_SPEED = 130; // svg px / second
export const MIN_WALK_DURATION = 1.1;

const corridorW = OFFICE.corridorWidth;

/** Where each zone's door meets the corridor (all rooms open onto the central cross). */
function zoneDoorPoint(zone: AgentZone): Point {
  if (zone === "corridor") return { ...ENTRANCE };
  const z = ZONES[zone];
  switch (zone) {
    case "desk":
    case "meeting":
      return { x: z.x + z.width / 2, y: z.y + z.height + corridorW / 2 };
    case "hotDesk":
    case "lounge":
      return { x: z.x + z.width / 2, y: z.y - corridorW / 2 };
  }
}

function sameCorridorArm(a: AgentZone, b: AgentZone): boolean {
  if (a === "corridor" || b === "corridor") return false;
  const pairs: AgentZone[][] = [
    ["desk", "hotDesk"],
    ["meeting", "lounge"],
    ["desk", "meeting"],
    ["hotDesk", "lounge"],
  ];
  return pairs.some((p) => p.includes(a) && p.includes(b));
}

/** Waypoint path from → fromDoor → (corridor centre) → toDoor → to. */
export function planWalkPath(from: Point, to: Point, fromZone: AgentZone, toZone: AgentZone): Point[] {
  if (fromZone === toZone) return [{ ...from }, { ...to }];

  const fromDoor = zoneDoorPoint(fromZone);
  const toDoor = zoneDoorPoint(toZone);

  // The entrance sits on the lounge's south wall: walks to/from the entrance
  // pass through the lounge door only when leaving the building side.
  if (fromZone === "corridor" && toZone === "lounge") return [{ ...from }, { ...to }];
  if (fromZone === "lounge" && toZone === "corridor") return [{ ...from }, { ...to }];

  if (fromZone === "corridor") {
    // Enter the building: entrance → lounge door → corridor → destination door.
    const loungeDoor = zoneDoorPoint("lounge");
    if (toZone === "meeting") return [{ ...from }, loungeDoor, toDoor, { ...to }];
    return [{ ...from }, loungeDoor, { ...CORRIDOR_CENTER }, toDoor, { ...to }];
  }
  if (toZone === "corridor") {
    const loungeDoor = zoneDoorPoint("lounge");
    if (fromZone === "meeting") return [{ ...from }, fromDoor, loungeDoor, { ...to }];
    return [{ ...from }, fromDoor, { ...CORRIDOR_CENTER }, loungeDoor, { ...to }];
  }

  if (sameCorridorArm(fromZone, toZone)) {
    return [{ ...from }, fromDoor, toDoor, { ...to }];
  }
  return [{ ...from }, fromDoor, { ...CORRIDOR_CENTER }, toDoor, { ...to }];
}

function distance(a: Point, b: Point): number {
  return Math.hypot(b.x - a.x, b.y - a.y);
}

export function pathLength(path: Point[]): number {
  let len = 0;
  for (let i = 1; i < path.length; i++) len += distance(path[i - 1], path[i]);
  return len;
}

export function walkDuration(path: Point[]): number {
  return Math.max(pathLength(path) / WALK_SPEED, MIN_WALK_DURATION);
}

/** Distance-proportional interpolation along a polyline. */
export function interpolatePath(path: Point[], progress: number): Point {
  if (path.length === 0) return { x: 0, y: 0 };
  if (progress <= 0) return { ...path[0] };
  if (progress >= 1) return { ...path[path.length - 1] };

  const total = pathLength(path);
  if (total === 0) return { ...path[0] };

  const target = progress * total;
  let acc = 0;
  for (let i = 1; i < path.length; i++) {
    const seg = distance(path[i - 1], path[i]);
    if (acc + seg >= target) {
      const t = seg > 0 ? (target - acc) / seg : 0;
      return {
        x: path[i - 1].x + (path[i].x - path[i - 1].x) * t,
        y: path[i - 1].y + (path[i].y - path[i - 1].y) * t,
      };
    }
    acc += seg;
  }
  return { ...path[path.length - 1] };
}
