import { Parser, Language, Query } from "web-tree-sitter";
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { resolve, dirname, join, isAbsolute } from "node:path";
import { fileURLToPath } from "node:url";
const __thisFile = fileURLToPath(import.meta.url);
function findAssetRoot() {
  if (existsSync(__thisFile) && !__thisFile.startsWith("/$bunfs") && !__thisFile.startsWith("bun:")) {
    return resolve(dirname(__thisFile), "..", "..");
  }
  const binDir = dirname(process.execPath);
  const candidates = [
    binDir,
    // assets next to binary
    resolve(binDir, ".."),
    // dev build project root
    resolve(binDir, "..", "share", "mapx"),
    // XDG system: /usr/local/share/mapx
    join(process.env["HOME"] ?? "", ".local", "share", "mapx")
    // XDG user
  ];
  for (const dir of candidates) {
    if (existsSync(join(dir, "wasm"))) return dir;
  }
  return binDir;
}
const PROJECT_ROOT = findAssetRoot();
let initPromise = null;
function ensureInit() {
  if (!initPromise) {
    initPromise = Parser.init({
      locateFile(path) {
        if (path === "web-tree-sitter.wasm") {
          return resolve(PROJECT_ROOT, "wasm", "web-tree-sitter.wasm");
        }
        return path;
      }
    });
  }
  return initPromise;
}
async function loadLanguage(langDef) {
  await ensureInit();
  const wasmPath = isAbsolute(langDef.grammarWasm) ? langDef.grammarWasm : resolve(PROJECT_ROOT, langDef.grammarWasm);
  const wasmBuffer = await readFile(wasmPath);
  const language = await Language.load(wasmBuffer);
  return language;
}
async function parseWithQueries(source, language, symbolsQuery, referencesQuery) {
  await ensureInit();
  const parser = new Parser();
  parser.setLanguage(language);
  const tree = parser.parse(source);
  if (!tree) {
    return { symbols: /* @__PURE__ */ new Map(), references: /* @__PURE__ */ new Map(), nameByNodeId: /* @__PURE__ */ new Map(), scopeByNodeId: /* @__PURE__ */ new Map() };
  }
  const symbolCaptures = /* @__PURE__ */ new Map();
  const refCaptures = /* @__PURE__ */ new Map();
  const nameByNodeId = /* @__PURE__ */ new Map();
  const scopeByNodeId = /* @__PURE__ */ new Map();
  try {
    const symQuery = new Query(language, symbolsQuery);
    const symMatches = symQuery.captures(tree.rootNode);
    const kindNodeIds = /* @__PURE__ */ new Set();
    for (const capture of symMatches) {
      const existing = symbolCaptures.get(capture.name) || [];
      existing.push(capture);
      symbolCaptures.set(capture.name, existing);
      if (capture.name.startsWith("symbol.kind_")) {
        kindNodeIds.add(capture.node.id);
      }
    }
    for (const capture of symMatches) {
      if (capture.name === "symbol.name") {
        let node = capture.node.parent;
        while (node) {
          if (kindNodeIds.has(node.id)) {
            nameByNodeId.set(node.id, capture.node.text);
            break;
          }
          node = node.parent;
        }
      } else if (capture.name === "symbol.scope") {
        let node = capture.node.parent;
        while (node) {
          if (kindNodeIds.has(node.id)) {
            scopeByNodeId.set(node.id, capture.node.text);
            break;
          }
          node = node.parent;
        }
      }
    }
  } catch (e) {
    if (!e.message?.includes("no query")) throw e;
  }
  try {
    const refQuery = new Query(language, referencesQuery);
    const refMatches = refQuery.captures(tree.rootNode);
    for (const capture of refMatches) {
      const existing = refCaptures.get(capture.name) || [];
      existing.push(capture);
      refCaptures.set(capture.name, existing);
    }
  } catch (e) {
    if (!e.message?.includes("no query")) throw e;
  }
  return { symbols: symbolCaptures, references: refCaptures, nameByNodeId, scopeByNodeId };
}
async function loadQueryFile(queryPath) {
  const fullPath = isAbsolute(queryPath) ? queryPath : resolve(PROJECT_ROOT, queryPath);
  return readFile(fullPath, "utf-8");
}
export {
  PROJECT_ROOT,
  loadLanguage,
  loadQueryFile,
  parseWithQueries
};
