/**
 * Child-process worker for parsing and extracting Java files in batch.
 *
 * Runs as: node scan-worker.js <input.json> <output.json> <includeSnippets>
 *
 * Input:  JSON array of file paths
 * Output: JSON array of { filePath, nodes, edges, status }
 *
 * When this process exits, the OS reclaims ALL native memory (tree-sitter ASTs).
 */

import { readFileSync, writeFileSync } from "node:fs";
import { extractFromFile } from "./extractor";
import { parseJavaFile } from "./parser";
import { regexExtractFromFile } from "./regex-extractor";
import { NodeType, EdgeType, type GraphNode, type GraphEdge } from "../types";

export interface WorkerResult {
  filePath: string;
  nodes: GraphNode[];
  edges: GraphEdge[];
  status: "complete" | "regex_fallback" | "parse_failed";
}

// Only run as main script (not when imported for types)
const isMain = typeof require !== "undefined" && require.main === module;
if (isMain) {
  const [, , inputPath, outputPath, snippetsArg] = process.argv;
  const includeSnippets = snippetsArg !== "false";
  const filePaths: string[] = JSON.parse(readFileSync(inputPath, "utf-8"));

  const results: WorkerResult[] = [];
  for (const filePath of filePaths) {
    results.push(processFile(filePath, includeSnippets));
  }

  writeFileSync(outputPath, JSON.stringify(results));
  process.exit(0);
}

function processFile(filePath: string, includeSnippets: boolean): WorkerResult {
  // Try tree-sitter parse + extract
  try {
    const { tree, source } = parseJavaFile(filePath);

    let nodes: GraphNode[];
    let edges: GraphEdge[];
    try {
      const result = extractFromFile(tree, filePath, source, includeSnippets);
      nodes = result.nodes;
      edges = result.edges;
    } catch {
      return tryRegexFallback(filePath, source);
    }

    // Check if tree-sitter found any classes
    const hasClasses = nodes.some(
      (n) => n.type === NodeType.CLASS || n.type === NodeType.INTERFACE || n.type === NodeType.ENUM,
    );

    if (!hasClasses && tree.rootNode.hasError) {
      try {
        const fallback = regexExtractFromFile(source, filePath);
        if (fallback.classCount > 0) {
          return { filePath, nodes: fallback.nodes, edges: fallback.edges, status: "regex_fallback" };
        }
      } catch { /* keep tree-sitter results */ }
    }

    // Supplement with regex-discovered methods tree-sitter missed
    if (hasClasses && tree.rootNode.hasError) {
      try {
        const fallback = regexExtractFromFile(source, filePath);
        const regexMethods = fallback.nodes.filter((n) => n.type === NodeType.METHOD);
        for (const rn of regexMethods) {
          const tsHas = nodes.some(
            (n) => n.type === NodeType.METHOD && n.name === rn.name &&
              n.location && rn.location &&
              Math.abs(n.location.lineStart - rn.location.lineStart) < 3,
          );
          if (!tsHas) {
            nodes.push(rn);
            const containsEdge = fallback.edges.find(
              (e) => e.target === rn.id && e.type === EdgeType.CONTAINS,
            );
            if (containsEdge) edges.push(containsEdge);
          }
        }
        const tsFieldNames = new Set(
          nodes.filter((n) => n.type === NodeType.FIELD).map((n) => n.name),
        );
        for (const rn of fallback.nodes.filter((n) => n.type === NodeType.FIELD)) {
          if (!tsFieldNames.has(rn.name)) {
            nodes.push(rn);
            const containsEdge = fallback.edges.find(
              (e) => e.target === rn.id && e.type === EdgeType.CONTAINS,
            );
            if (containsEdge) edges.push(containsEdge);
          }
        }
      } catch { /* keep tree-sitter results */ }
    }

    return { filePath, nodes, edges, status: "complete" };
  } catch {
    // Parse failed — try regex on raw source
    try {
      const rawSource = readFileSync(filePath, "utf-8");
      return tryRegexFallback(filePath, rawSource);
    } catch {
      return { filePath, nodes: [], edges: [], status: "parse_failed" };
    }
  }
}

function tryRegexFallback(filePath: string, source: string): WorkerResult {
  try {
    const fallback = regexExtractFromFile(source, filePath);
    if (fallback.classCount > 0) {
      return { filePath, nodes: fallback.nodes, edges: fallback.edges, status: "regex_fallback" };
    }
  } catch { /* ignore */ }
  return { filePath, nodes: [], edges: [], status: "parse_failed" };
}
