// Zone-layout decision tree, ported from the AHK `act-decoder`.
//
// The bundled PoE2 layout images (static/layouts/) are named `<areaID> <path>.jpg`
// where the path is a decision tree encoded as underscore-separated segments:
//   "1", "2", "3"      = the candidate layouts you first see entering a zone
//   "3_1", "3_2"       = refinements of "3" revealed as you explore deeper
//   "x", "x_x"         = the zone's legend pages (key to the map symbols), NOT
//                        decision candidates — they're shown persistently.
// You pick the candidate matching what you see in-game, then keep refining until
// no children remain. (On disk the space is stored as "~" for URL-safe serving.)

export type LayoutManifest = Record<string, string[]>; // areaID -> sorted paths

let manifestPromise: Promise<LayoutManifest> | null = null;

/** Load (once) the areaID -> paths manifest generated at build time. */
export function loadManifest(): Promise<LayoutManifest> {
  if (!manifestPromise) {
    manifestPromise = fetch("/layouts/index.json")
      .then((r) => (r.ok ? r.json() : {}))
      .catch(() => ({}));
  }
  return manifestPromise;
}

/** URL of the image for a given area + decision path. */
export function imageUrl(areaId: string, path: string): string {
  return `/layouts/${areaId}~${path}.jpg`;
}

const depth = (p: string): number => (p === "" ? 0 : p.split("_").length);

/** Order paths numerically per segment, "x" sorting last. */
function sortPaths(a: string, b: string): number {
  const sa = a.split("_");
  const sb = b.split("_");
  const n = Math.min(sa.length, sb.length);
  for (let i = 0; i < n; i++) {
    if (sa[i] !== sb[i]) {
      const na = sa[i] === "x" ? Infinity : parseInt(sa[i], 10);
      const nb = sb[i] === "x" ? Infinity : parseInt(sb[i], 10);
      return na - nb;
    }
  }
  return sa.length - sb.length;
}

/**
 * Direct children of `path` ("" = root) among `paths`: entries one segment
 * deeper that extend `path`.
 */
export function childrenOf(paths: string[], path: string): string[] {
  const want = depth(path) + 1;
  const prefix = path === "" ? "" : path + "_";
  return paths
    .filter((p) => p !== path && depth(p) === want && (path === "" || p.startsWith(prefix)))
    .sort(sortPaths);
}

/**
 * A path is a legend page rather than a layout candidate. These are named with
 * a leading "x" segment ("x", "x_x", …) and hold the key to the map symbols, so
 * the viewer pulls them out of the decision tree and keeps them always visible.
 */
export function isLegend(path: string): boolean {
  return path.split("_")[0] === "x";
}

// Zones whose layout placement is fixed (or where rotation gave wrong results in
// the original), so the viewer hides its rotation controls. Ported from the AHK
// `rota_block`; keys there may be "<areaID>" or "<areaID> <path>" — we block the
// whole area if any key matches (a single orientation is applied per zone).
const ROTA_BLOCK_AREAS = new Set([
  "g1_2", "g1_4", "g1_7", "g1_8", "g1_11", "g1_12", "g1_14", "g1_15",
  "g2_2", "g2_4_3", "g2_6", "g3_11", "g3_16",
]);

export function rotationBlocked(areaId: string): boolean {
  return ROTA_BLOCK_AREAS.has(areaId);
}
