#!/usr/bin/env node
import {
  detectLanguage,
  emptyIndex,
  loadIndex,
  removeFile,
  saveIndex,
  upsertFileSymbols
} from "./chunk-OVWE4E46.js";

// src/symbols/indexer.ts
import fs2 from "fs";
import path3 from "path";

// src/symbols/parser.ts
import path2 from "path";

// src/symbols/loader.ts
import { Parser, Language } from "web-tree-sitter";
import { createRequire } from "module";
import path from "path";
import fs from "fs";
import { fileURLToPath } from "url";
var _metaUrl = import.meta?.url;
var _cjsFilename = globalThis.__filename;
var __filename_ = _metaUrl ? fileURLToPath(_metaUrl) : _cjsFilename ?? process.execPath;
var __dirname_ = path.dirname(__filename_);
var require_ = _metaUrl ? createRequire(_metaUrl) : createRequire(__filename_);
var GRAMMAR_FILE = {
  typescript: "tree-sitter-typescript.wasm",
  tsx: "tree-sitter-tsx.wasm",
  javascript: "tree-sitter-javascript.wasm",
  python: "tree-sitter-python.wasm",
  go: "tree-sitter-go.wasm",
  rust: "tree-sitter-rust.wasm",
  java: "tree-sitter-java.wasm",
  cpp: "tree-sitter-cpp.wasm"
};
var RUNTIME_WASM = "web-tree-sitter.wasm";
var parserInitPromise = null;
var languageCache = /* @__PURE__ */ new Map();
var parserCache = /* @__PURE__ */ new Map();
function resolveWasmPath(filename) {
  const candidates = [];
  candidates.push(path.join(__dirname_, "wasm", filename));
  candidates.push(path.join(__dirname_, "..", "wasm", filename));
  candidates.push(path.join(__dirname_, "..", "dist", "wasm", filename));
  if (process.pkg) {
    candidates.push(path.join(path.dirname(process.execPath), "dist", "wasm", filename));
    candidates.push(path.join("/snapshot", "ai-cli", "dist", "wasm", filename));
    candidates.push(path.join("/snapshot", "jinzd-ai-cli", "dist", "wasm", filename));
  }
  const resourcesPath = process.resourcesPath;
  if (resourcesPath) {
    candidates.push(path.join(resourcesPath, "app.asar.unpacked", "dist", "wasm", filename));
    candidates.push(path.join(resourcesPath, "app", "dist", "wasm", filename));
  }
  try {
    if (filename === RUNTIME_WASM) {
      const pkgPath = require_.resolve("web-tree-sitter/package.json");
      candidates.push(path.join(path.dirname(pkgPath), filename));
    } else {
      const grammarPkg = filename.replace(/\.wasm$/, "").replace(/^tree-sitter-tsx$/, "tree-sitter-typescript");
      const pkgPath = require_.resolve(`${grammarPkg}/package.json`);
      candidates.push(path.join(path.dirname(pkgPath), filename));
    }
  } catch {
  }
  candidates.push(path.join(process.cwd(), "dist", "wasm", filename));
  candidates.push(path.join(process.cwd(), "node_modules", "web-tree-sitter", filename));
  for (const p of candidates) {
    try {
      if (fs.existsSync(p)) return p;
    } catch {
    }
  }
  throw new Error(
    `[symbols/loader] Cannot locate ${filename}. Searched:
  ${candidates.join("\n  ")}`
  );
}
async function initRuntime() {
  if (parserInitPromise) return parserInitPromise;
  parserInitPromise = Parser.init({
    locateFile: (name) => resolveWasmPath(name)
  });
  return parserInitPromise;
}
async function loadParser(language) {
  const cached = parserCache.get(language);
  if (cached) return cached;
  await initRuntime();
  let lang = languageCache.get(language);
  if (!lang) {
    const wasmPath = resolveWasmPath(GRAMMAR_FILE[language]);
    lang = await Language.load(wasmPath);
    languageCache.set(language, lang);
  }
  const parser = new Parser();
  parser.setLanguage(lang);
  parserCache.set(language, parser);
  return parser;
}

// src/symbols/parser.ts
function locationOf(file, node) {
  return {
    file: path2.resolve(file),
    line: node.startPosition.row + 1,
    column: node.startPosition.column,
    endLine: node.endPosition.row + 1,
    endColumn: node.endPosition.column
  };
}
function firstLine(text, max = 200) {
  const line = text.split(/\r?\n/)[0] ?? "";
  return line.length > max ? line.slice(0, max) + "\u2026" : line;
}
function childByFieldName(node, field) {
  return node.childForFieldName(field) ?? null;
}
function nameOf(node) {
  const n = childByFieldName(node, "name") ?? node.children.find((c) => c?.type === "identifier" || c?.type === "property_identifier" || c?.type === "type_identifier");
  return n?.text ?? null;
}
function extractTsJs(root, file, language) {
  const out = [];
  const visit = (node, container, exported) => {
    let childrenContainer = container;
    const kindMap = {
      function_declaration: "function",
      generator_function_declaration: "function",
      class_declaration: "class",
      abstract_class_declaration: "class",
      interface_declaration: "interface",
      type_alias_declaration: "type",
      enum_declaration: "enum",
      method_definition: "method",
      method_signature: "method",
      public_field_definition: "property"
    };
    const kind = kindMap[node.type];
    if (kind) {
      const name = nameOf(node);
      if (name) {
        out.push({
          name,
          kind,
          language,
          location: locationOf(file, node),
          signature: firstLine(node.text),
          container,
          exported
        });
        if (kind === "class" || kind === "interface" || kind === "enum") {
          childrenContainer = name;
        }
      }
    } else if (node.type === "lexical_declaration" || node.type === "variable_declaration") {
      for (const decl of node.children) {
        if (decl?.type !== "variable_declarator") continue;
        const nameNode = childByFieldName(decl, "name");
        if (!nameNode || nameNode.type !== "identifier") continue;
        out.push({
          name: nameNode.text,
          kind: "variable",
          language,
          location: locationOf(file, decl),
          signature: firstLine(decl.text),
          container,
          exported
        });
      }
    } else if (node.type === "export_statement") {
      for (const c of node.children) {
        if (c) visit(c, container, true);
      }
      return;
    }
    const descendInto = /* @__PURE__ */ new Set([
      "program",
      "module",
      "class_body",
      "class_declaration",
      "abstract_class_declaration",
      "interface_body",
      "interface_declaration",
      "enum_body",
      "enum_declaration",
      "export_statement",
      "statement_block",
      // for nested class_declaration inside namespace etc.
      "internal_module",
      "namespace_declaration"
    ]);
    if (node === root || descendInto.has(node.type)) {
      for (const c of node.children) {
        if (c) visit(c, childrenContainer, exported);
      }
    }
  };
  visit(root, void 0, false);
  return out;
}
function extractPython(root, file) {
  const out = [];
  const visit = (node, container, isModuleLevel) => {
    if (node.type === "decorated_definition") {
      const def = node.children.find(
        (c) => c?.type === "class_definition" || c?.type === "function_definition"
      );
      if (def) visit(def, container, isModuleLevel);
      return;
    }
    if (node.type === "class_definition") {
      const name = nameOf(node);
      if (name) {
        out.push({
          name,
          kind: "class",
          language: "python",
          location: locationOf(file, node),
          signature: firstLine(node.text),
          container,
          exported: isModuleLevel
        });
        const body = childByFieldName(node, "body");
        if (body) {
          for (const c of body.children) {
            if (c) visit(c, name, false);
          }
        }
      }
      return;
    }
    if (node.type === "function_definition") {
      const name = nameOf(node);
      if (name) {
        out.push({
          name,
          kind: container ? "method" : "function",
          language: "python",
          location: locationOf(file, node),
          signature: firstLine(node.text),
          container,
          exported: isModuleLevel && !name.startsWith("_")
        });
      }
      return;
    }
    if (isModuleLevel && node.type === "expression_statement") {
      const assign = node.children.find((c) => c?.type === "assignment");
      if (assign) {
        const left = childByFieldName(assign, "left");
        if (left && left.type === "identifier") {
          out.push({
            name: left.text,
            kind: "variable",
            language: "python",
            location: locationOf(file, assign),
            signature: firstLine(assign.text),
            container,
            exported: !left.text.startsWith("_")
          });
        }
      }
      return;
    }
    if (node === root || node.type === "module") {
      for (const c of node.children) {
        if (c) visit(c, container, true);
      }
    }
  };
  visit(root, void 0, true);
  return out;
}
function extractGo(root, file) {
  const out = [];
  const isExported = (name) => /^[A-Z]/.test(name);
  const pushTypeSpec = (spec) => {
    const name = nameOf(spec);
    if (!name) return;
    const typeNode = childByFieldName(spec, "type");
    let kind = "type";
    if (typeNode?.type === "struct_type") kind = "class";
    else if (typeNode?.type === "interface_type") kind = "interface";
    out.push({
      name,
      kind,
      language: "go",
      location: locationOf(file, spec),
      signature: firstLine(spec.text),
      exported: isExported(name)
    });
  };
  for (const child of root.children) {
    if (!child) continue;
    if (child.type === "function_declaration") {
      const name = nameOf(child);
      if (name) out.push({ name, kind: "function", language: "go", location: locationOf(file, child), signature: firstLine(child.text), exported: isExported(name) });
    } else if (child.type === "method_declaration") {
      const name = nameOf(child);
      if (!name) continue;
      const receiver = childByFieldName(child, "receiver");
      let container;
      if (receiver) {
        const paramDecl = receiver.children.find((c) => c?.type === "parameter_declaration");
        const typeNode = paramDecl ? childByFieldName(paramDecl, "type") : null;
        if (typeNode) {
          container = typeNode.text.replace(/^\*/, "").trim();
        }
      }
      out.push({ name, kind: "method", language: "go", location: locationOf(file, child), signature: firstLine(child.text), container, exported: isExported(name) });
    } else if (child.type === "type_declaration") {
      for (const spec of child.children) {
        if (spec?.type === "type_spec" || spec?.type === "type_alias") pushTypeSpec(spec);
      }
    } else if (child.type === "const_declaration" || child.type === "var_declaration") {
      for (const spec of child.children) {
        if (spec?.type !== "const_spec" && spec?.type !== "var_spec") continue;
        for (const id of spec.children) {
          if (id?.type !== "identifier") continue;
          out.push({ name: id.text, kind: "variable", language: "go", location: locationOf(file, spec), signature: firstLine(spec.text), exported: isExported(id.text) });
        }
      }
    }
  }
  return out;
}
function extractRust(root, file) {
  const out = [];
  const isPub = (node) => node.children.some((c) => c?.type === "visibility_modifier" && c.text.startsWith("pub"));
  const visit = (node, container) => {
    const kindMap = {
      function_item: container ? "method" : "function",
      struct_item: "class",
      union_item: "class",
      enum_item: "enum",
      trait_item: "interface",
      type_item: "type",
      const_item: "variable",
      static_item: "variable",
      macro_definition: "function",
      mod_item: "module"
    };
    const kind = kindMap[node.type];
    if (kind) {
      const name = nameOf(node);
      if (name) {
        out.push({ name, kind, language: "rust", location: locationOf(file, node), signature: firstLine(node.text), container, exported: isPub(node) });
        if (node.type === "mod_item") {
          const body = childByFieldName(node, "body");
          if (body) for (const c of body.children) {
            if (c) visit(c, name);
          }
        }
      }
      return;
    }
    if (node.type === "impl_item") {
      const typeNode = childByFieldName(node, "type");
      const implContainer = typeNode?.text.trim();
      const body = childByFieldName(node, "body");
      if (body) for (const c of body.children) {
        if (c) visit(c, implContainer);
      }
      return;
    }
    if (node.type === "source_file" || node.type === "declaration_list") {
      for (const c of node.children) {
        if (c) visit(c, container);
      }
    }
  };
  visit(root, void 0);
  return out;
}
function extractJava(root, file) {
  const out = [];
  const isPublic = (node) => {
    const mods = node.children.find((c) => c?.type === "modifiers");
    return !!mods && mods.children.some((c) => c?.type === "public" || c?.text === "public");
  };
  const visit = (node, container) => {
    const containerKindMap = {
      class_declaration: "class",
      interface_declaration: "interface",
      enum_declaration: "enum",
      record_declaration: "class",
      annotation_type_declaration: "interface"
    };
    const containerKind = containerKindMap[node.type];
    if (containerKind) {
      const name = nameOf(node);
      if (name) {
        out.push({ name, kind: containerKind, language: "java", location: locationOf(file, node), signature: firstLine(node.text), container, exported: isPublic(node) });
        const body = node.children.find((c) => c?.type === "class_body" || c?.type === "interface_body" || c?.type === "enum_body" || c?.type === "record_body" || c?.type === "annotation_type_body");
        if (body) for (const c of body.children) {
          if (c) visit(c, name);
        }
      }
      return;
    }
    if (node.type === "method_declaration" || node.type === "constructor_declaration" || node.type === "compact_constructor_declaration") {
      const name = nameOf(node);
      if (name) out.push({ name, kind: "method", language: "java", location: locationOf(file, node), signature: firstLine(node.text), container, exported: isPublic(node) });
      return;
    }
    if (node.type === "field_declaration") {
      const exported = isPublic(node);
      for (const c of node.children) {
        if (c?.type !== "variable_declarator") continue;
        const id = childByFieldName(c, "name");
        if (id?.type === "identifier") out.push({ name: id.text, kind: "property", language: "java", location: locationOf(file, c), signature: firstLine(node.text), container, exported });
      }
      return;
    }
    if (node.type === "program") {
      for (const c of node.children) {
        if (c) visit(c, container);
      }
    }
  };
  visit(root, void 0);
  return out;
}
function extractCpp(root, file) {
  const out = [];
  const declaratorName = (decl) => {
    if (!decl) return null;
    if (decl.type === "identifier" || decl.type === "field_identifier" || decl.type === "type_identifier") {
      return { name: decl.text };
    }
    if (decl.type === "qualified_identifier") {
      const text = decl.text;
      const idx = text.lastIndexOf("::");
      if (idx >= 0) return { name: text.slice(idx + 2), container: text.slice(0, idx) };
      return { name: text };
    }
    if (decl.type === "destructor_name" || decl.type === "operator_name") {
      return { name: decl.text };
    }
    const inner = childByFieldName(decl, "declarator");
    if (inner) return declaratorName(inner);
    return null;
  };
  const visit = (node, container) => {
    if (node.type === "template_declaration") {
      for (const c of node.children) {
        if (c && (c.type === "function_definition" || c.type === "class_specifier" || c.type === "struct_specifier" || c.type === "declaration")) {
          visit(c, container);
        }
      }
      return;
    }
    if (node.type === "function_definition") {
      const decl = childByFieldName(node, "declarator");
      const info = declaratorName(decl);
      if (info) {
        const finalContainer = info.container ?? container;
        out.push({
          name: info.name,
          kind: finalContainer ? "method" : "function",
          language: "cpp",
          location: locationOf(file, node),
          signature: firstLine(node.text),
          container: finalContainer
        });
      }
      return;
    }
    const specMap = {
      class_specifier: "class",
      struct_specifier: "class",
      union_specifier: "class",
      enum_specifier: "enum"
    };
    const specKind = specMap[node.type];
    if (specKind) {
      const name = nameOf(node);
      if (name) {
        out.push({ name, kind: specKind, language: "cpp", location: locationOf(file, node), signature: firstLine(node.text), container });
        const body = node.children.find((c) => c?.type === "field_declaration_list" || c?.type === "enumerator_list");
        if (body) for (const c of body.children) {
          if (c) visit(c, name);
        }
      }
      return;
    }
    if (node.type === "namespace_definition") {
      const name = nameOf(node) ?? "<anonymous>";
      out.push({ name, kind: "module", language: "cpp", location: locationOf(file, node), signature: firstLine(node.text), container });
      const body = childByFieldName(node, "body");
      if (body) for (const c of body.children) {
        if (c) visit(c, name);
      }
      return;
    }
    if (node.type === "type_definition" || node.type === "alias_declaration") {
      const decl = node.children[node.children.length - 1];
      const info = decl ? declaratorName(decl) : null;
      if (info) out.push({ name: info.name, kind: "type", language: "cpp", location: locationOf(file, node), signature: firstLine(node.text), container });
      return;
    }
    if (node.type === "field_declaration" && container) {
      const hasFn = node.children.some((c) => c?.type === "function_declarator" || c?.type === "pointer_declarator" && c.children.some((x) => x?.type === "function_declarator"));
      if (hasFn) return;
      for (const c of node.children) {
        if (c?.type === "field_identifier") {
          out.push({ name: c.text, kind: "property", language: "cpp", location: locationOf(file, node), signature: firstLine(node.text), container });
        }
      }
      return;
    }
    if (node.type === "translation_unit" || node.type === "declaration_list" || node.type === "linkage_specification") {
      for (const c of node.children) {
        if (c) visit(c, container);
      }
    }
  };
  visit(root, void 0);
  return out;
}
async function parseSource(file, source, language) {
  const lang = language ?? detectLanguage(path2.extname(file).slice(1));
  if (!lang) return [];
  try {
    const parser = await loadParser(lang);
    const tree = parser.parse(source);
    if (!tree) return [];
    const root = tree.rootNode;
    switch (lang) {
      case "python":
        return extractPython(root, file);
      case "go":
        return extractGo(root, file);
      case "rust":
        return extractRust(root, file);
      case "java":
        return extractJava(root, file);
      case "cpp":
        return extractCpp(root, file);
      default:
        return extractTsJs(root, file, lang);
    }
  } catch (err) {
    return [];
  }
}

// src/symbols/indexer.ts
var SKIP_DIRS = /* @__PURE__ */ new Set([
  "node_modules",
  ".git",
  "dist",
  "dist-cjs",
  "build",
  "out",
  "coverage",
  ".next",
  ".nuxt",
  ".turbo",
  ".cache",
  "__pycache__",
  ".venv",
  "venv",
  ".idea",
  ".vscode",
  "release",
  "target",
  // Rust (cargo build) + Java (Maven)
  "vendor",
  // Go (vendored deps)
  ".gradle",
  // Java (Gradle)
  "cmake-build-debug",
  "cmake-build-release"
]);
var MAX_FILE_BYTES = 2 * 1024 * 1024;
function collectFiles(root, maxFiles) {
  const out = [];
  const stack = [root];
  while (stack.length > 0 && out.length < maxFiles) {
    const dir = stack.pop();
    let entries;
    try {
      entries = fs2.readdirSync(dir, { withFileTypes: true });
    } catch {
      continue;
    }
    for (const e of entries) {
      const full = path3.join(dir, e.name);
      if (e.isDirectory()) {
        if (SKIP_DIRS.has(e.name)) continue;
        if (e.name.startsWith(".") && e.name !== ".") {
          continue;
        }
        stack.push(full);
      } else if (e.isFile()) {
        const ext = path3.extname(e.name).slice(1);
        if (detectLanguage(ext)) {
          out.push(full);
          if (out.length >= maxFiles) break;
        }
      }
    }
  }
  return out;
}
async function indexProject(root, opts = {}) {
  const start = Date.now();
  const maxFiles = opts.maxFiles ?? 5e3;
  const force = opts.force === true;
  const absRoot = path3.resolve(root);
  let index = force ? emptyIndex(absRoot) : loadIndex(absRoot) ?? emptyIndex(absRoot);
  const files = collectFiles(absRoot, maxFiles);
  const liveSet = new Set(files.map((f) => path3.resolve(f)));
  for (const known of Object.keys(index.files)) {
    if (!liveSet.has(known)) {
      index = removeFile(index, known);
    }
  }
  let parsed = 0;
  let skipped = 0;
  for (let i = 0; i < files.length; i++) {
    const file = path3.resolve(files[i]);
    let stat;
    try {
      stat = fs2.statSync(file);
    } catch {
      skipped++;
      continue;
    }
    if (stat.size > MAX_FILE_BYTES) {
      skipped++;
      continue;
    }
    const prevMtime = index.files[file];
    if (!force && prevMtime !== void 0 && prevMtime === stat.mtimeMs) {
      continue;
    }
    let src;
    try {
      src = fs2.readFileSync(file, "utf-8");
    } catch {
      skipped++;
      continue;
    }
    const symbols = await parseSource(file, src);
    index = upsertFileSymbols(index, file, stat.mtimeMs, symbols);
    parsed++;
    if (opts.onProgress && parsed % 50 === 0) {
      opts.onProgress(i + 1, files.length);
    }
  }
  saveIndex(index);
  return {
    index,
    stats: {
      filesScanned: files.length,
      filesParsed: parsed,
      filesSkipped: skipped,
      symbols: index.symbolCount,
      durationMs: Date.now() - start
    }
  };
}
async function updateFile(root, file) {
  const absRoot = path3.resolve(root);
  const absFile = path3.resolve(file);
  let index = loadIndex(absRoot);
  if (!index) return;
  if (!fs2.existsSync(absFile)) {
    index = removeFile(index, absFile);
    saveIndex(index);
    return;
  }
  const ext = path3.extname(absFile).slice(1);
  if (!detectLanguage(ext)) return;
  let stat;
  try {
    stat = fs2.statSync(absFile);
  } catch {
    return;
  }
  if (stat.size > MAX_FILE_BYTES) return;
  let src;
  try {
    src = fs2.readFileSync(absFile, "utf-8");
  } catch {
    return;
  }
  const symbols = await parseSource(absFile, src);
  index = upsertFileSymbols(index, absFile, stat.mtimeMs, symbols);
  saveIndex(index);
}

export {
  indexProject,
  updateFile
};
