import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { existsSync } from "node:fs";
class FlutterDetector {
  name = "flutter";
  language = "dart";
  filePattern = /\.dart$/;
  async detect(projectRoot, files) {
    const pubspec = join(projectRoot, "pubspec.yaml");
    if (existsSync(pubspec)) {
      try {
        const content = await readFile(pubspec, "utf-8");
        if (content.includes("flutter:") && content.includes("sdk: flutter")) {
          return true;
        }
      } catch {
      }
    }
    return files.some((f) => f.endsWith("lib/main.dart") || f.endsWith("/lib/main.dart"));
  }
  async extractRoutes(filePath, content, ctx) {
    const routes = [];
    if (!filePath.endsWith(".dart")) return routes;
    const pushNamedRe = /Navigator\.\w*pushNamed\w*\s*\(\s*\w+\s*,\s*['"]([^'"]+)['"]/g;
    let m;
    while ((m = pushNamedRe.exec(content)) !== null) {
      routes.push({
        framework: this.name,
        method: "NAVIGATE",
        path: m[1],
        handlerFile: filePath,
        handlerSymbol: void 0,
        metadata: { confidence: "inferred", routeType: "navigator-named" }
      });
    }
    const routesMapRe = /['"]([/][^'"]*)['"]\s*:\s*\([^)]*\)\s*=>\s*([A-Z][a-zA-Z0-9_]*)/g;
    while ((m = routesMapRe.exec(content)) !== null) {
      const widgetName = m[2];
      let resolvedFile = filePath;
      const resolved = ctx.resolveSymbolToFile(widgetName);
      if (resolved) resolvedFile = resolved;
      routes.push({
        framework: this.name,
        method: "NAVIGATE",
        path: m[1],
        handlerFile: resolvedFile,
        handlerSymbol: widgetName,
        metadata: { confidence: "inferred", routeType: "routes-map" }
      });
    }
    const goRouteRe = /GoRoute\s*\(\s*(?:[^)]*?)path\s*:\s*['"]([^'"]+)['"]/g;
    while ((m = goRouteRe.exec(content)) !== null) {
      const path = m[1];
      const afterRoute = content.slice(m.index, m.index + 400);
      const builderMatch = afterRoute.match(/(?:builder|pageBuilder)\s*:\s*[^,]*?(?:=>|return)\s+([A-Z][a-zA-Z0-9_]*)/);
      const widgetName = builderMatch?.[1];
      let resolvedFile = filePath;
      if (widgetName) {
        const resolved = ctx.resolveSymbolToFile(widgetName);
        if (resolved) resolvedFile = resolved;
      }
      routes.push({
        framework: this.name,
        method: "NAVIGATE",
        path,
        handlerFile: resolvedFile,
        handlerSymbol: widgetName,
        metadata: { confidence: "inferred", routeType: "go-router" }
      });
    }
    const autoRouteRe = /@RoutePage\(\)\s*\n\s*(?:abstract\s+)?class\s+([A-Z][a-zA-Z0-9_]*)/g;
    while ((m = autoRouteRe.exec(content)) !== null) {
      const widgetName = m[1];
      const inferredPath = "/" + widgetName.replace(/Page$|Screen$|View$/, "").replace(/([A-Z])/g, (match, _p1, offset) => (offset > 0 ? "-" : "") + match.toLowerCase());
      routes.push({
        framework: this.name,
        method: "NAVIGATE",
        path: inferredPath,
        handlerFile: filePath,
        handlerSymbol: widgetName,
        metadata: { confidence: "inferred", routeType: "auto-route" }
      });
    }
    return routes;
  }
  async extractHooks(filePath, content, ctx) {
    const hooks = [];
    if (!filePath.endsWith(".dart")) return hooks;
    const lifecycleMethods = [
      { name: "initState", hookType: "lifecycle" },
      { name: "dispose", hookType: "lifecycle" },
      { name: "build", hookType: "render" },
      { name: "didChangeDependencies", hookType: "lifecycle" },
      { name: "didUpdateWidget", hookType: "lifecycle" },
      { name: "setState", hookType: "state-update" },
      { name: "deactivate", hookType: "lifecycle" },
      { name: "reassemble", hookType: "lifecycle" }
    ];
    for (const { name, hookType } of lifecycleMethods) {
      const re = new RegExp(`@override\\s*\\n\\s*(?:\\w+\\s+)?${name}\\s*\\(`, "g");
      let m;
      while ((m = re.exec(content)) !== null) {
        const line = content.slice(0, m.index).split("\n").length;
        const before = content.slice(0, m.index);
        const classMatch = [...before.matchAll(/\bclass\s+([A-Z][a-zA-Z0-9_]*)/g)].pop();
        const className = classMatch?.[1];
        hooks.push({
          framework: this.name,
          hookName: name,
          hookType,
          handlerFile: filePath,
          handlerSymbol: className ? `${className}@${name}` : name,
          metadata: { line }
        });
      }
    }
    const statePatterns = [
      { re: /\bConsumer\s*\(/g, hookName: "Consumer", hookType: "state-provider" },
      { re: /\bConsumerWidget\b/g, hookName: "ConsumerWidget", hookType: "state-provider" },
      { re: /\bConsumerStatefulWidget\b/g, hookName: "ConsumerStatefulWidget", hookType: "state-provider" },
      { re: /context\.watch\s*</g, hookName: "context.watch", hookType: "state-provider" },
      { re: /context\.read\s*</g, hookName: "context.read", hookType: "state-provider" },
      { re: /ref\.watch\s*\(/g, hookName: "ref.watch", hookType: "riverpod" },
      { re: /ref\.read\s*\(/g, hookName: "ref.read", hookType: "riverpod" },
      { re: /BlocBuilder\s*</g, hookName: "BlocBuilder", hookType: "bloc" },
      { re: /BlocListener\s*</g, hookName: "BlocListener", hookType: "bloc" },
      { re: /BlocConsumer\s*</g, hookName: "BlocConsumer", hookType: "bloc" },
      { re: /MultiBlocProvider\s*\(/g, hookName: "MultiBlocProvider", hookType: "bloc" },
      { re: /GetBuilder\s*</g, hookName: "GetBuilder", hookType: "getx" },
      { re: /Obx\s*\(/g, hookName: "Obx", hookType: "getx" },
      { re: /GetX\s*</g, hookName: "GetX", hookType: "getx" }
    ];
    for (const { re, hookName, hookType } of statePatterns) {
      if (re.test(content)) {
        hooks.push({
          framework: this.name,
          hookName,
          hookType,
          handlerFile: filePath,
          metadata: { confidence: "inferred" }
        });
      }
    }
    return hooks;
  }
}
export {
  FlutterDetector
};
