import picomatch from "picomatch";
import * as path from "node:path";
class RoleClassifier {
  constructor(store, config) {
    this.store = store;
    this.config = config;
    this.configSettings = config?.settings?.architecture || {};
  }
  store;
  config;
  configSettings;
  /**
   * Classifies a file and stores its signals, alternate roles, and confidence scores.
   */
  classify(filePath, repoName, profile, routes = [], hooks = []) {
    const overrideRole = this.getOverrideRole(filePath);
    if (overrideRole) {
      return {
        filePath,
        role: overrideRole,
        confidence: 1,
        signals: [
          {
            source: "path",
            role: overrideRole,
            confidence: 1,
            reason: `Explicitly overridden in config.json settings`
          }
        ],
        alternateRoles: []
      };
    }
    const ext = path.extname(filePath).toLowerCase();
    if (ext === ".md" || ext === ".markdown" || ext === ".mdx") {
      return {
        filePath,
        role: "docs",
        confidence: 1,
        signals: [
          {
            source: "path",
            role: "docs",
            confidence: 1,
            reason: "Markdown files are always classified as documentation (docs)"
          }
        ],
        alternateRoles: []
      };
    }
    const signals = [];
    const pathSignal = this.getPathSignal(filePath, profile);
    if (pathSignal) {
      signals.push(pathSignal);
    }
    const namingSignal = this.getNamingSignal(filePath);
    if (namingSignal) {
      signals.push(namingSignal);
    }
    const topologySignal = this.getTopologySignal(filePath, profile);
    if (topologySignal) {
      signals.push(topologySignal);
    }
    const frameworkSignal = this.getFrameworkSignal(filePath, routes, hooks);
    if (frameworkSignal) {
      signals.push(frameworkSignal);
    }
    const importsSignal = this.getImportsSignal(filePath);
    if (importsSignal) {
      signals.push(importsSignal);
    }
    const weights = {
      path: 0.3,
      naming: 0.25,
      topology: 0.2,
      framework: 0.15,
      imports: 0.1
    };
    const roleScores = {};
    const roleReasons = {};
    for (const sig of signals) {
      const w = weights[sig.source];
      roleScores[sig.role] = (roleScores[sig.role] || 0) + sig.confidence * w;
      if (!roleReasons[sig.role]) {
        roleReasons[sig.role] = [];
      }
      roleReasons[sig.role].push(`[${sig.source}] ${sig.reason}`);
    }
    const sortedRoles = Object.entries(roleScores).sort((a, b) => b[1] - a[1]).map((e) => e[0]);
    const finalRole = sortedRoles[0] || "other";
    const totalPossibleWeight = Object.keys(weights).reduce((sum, key) => sum + weights[key], 0);
    const confidence = sortedRoles.length > 0 ? Math.min(1, roleScores[finalRole] / totalPossibleWeight) : 0.5;
    return {
      filePath,
      role: finalRole,
      confidence,
      signals,
      alternateRoles: sortedRoles.slice(1)
    };
  }
  getOverrideRole(filePath) {
    const overrides = this.configSettings.overrides || {};
    for (const [pattern, role] of Object.entries(overrides)) {
      if (picomatch.isMatch(filePath, pattern, { dot: true })) {
        return role;
      }
    }
    const customRoles = this.configSettings.customRoles || [];
    for (const custom of customRoles) {
      const patterns = Array.isArray(custom.paths) ? custom.paths : [custom.paths];
      for (const p of patterns) {
        if (picomatch.isMatch(filePath, p, { dot: true })) {
          return custom.name;
        }
      }
    }
    return null;
  }
  getPathSignal(filePath, profile) {
    const lower = filePath.toLowerCase();
    const basename = path.basename(lower);
    const parts = lower.split("/");
    if (parts.some((p) => p === "tests" || p === "test" || p === "__tests__" || p === "spec" || p === "specs") || /\.(test|spec)\.[a-z0-9]+$/.test(lower)) {
      return { source: "path", role: "test", confidence: 0.95, reason: "Matched test path pattern" };
    }
    if (parts.some((p) => p === "docs" || p === "documentation") || basename.endsWith(".md") || basename.endsWith(".mdx")) {
      return { source: "path", role: "docs", confidence: 0.95, reason: "Matched documentation file pattern" };
    }
    if (parts.some((p) => p === "config" || p === "configs" || p === "configuration") || /\.(config|env|rc)\.[a-z0-9]+$/.test(lower) || basename.endsWith(".env")) {
      return { source: "path", role: "config", confidence: 0.95, reason: "Matched configuration file pattern" };
    }
    if (parts.some((p) => p === "types" || p === "interfaces" || p === "typings") || basename.endsWith(".d.ts") || basename === "types.ts" || basename === "interfaces.ts" || /\.types\.[a-z0-9]+$/.test(lower) || /\.interface\.[a-z0-9]+$/.test(lower)) {
      return { source: "path", role: "types", confidence: 0.95, reason: "Matched types/interfaces file pattern" };
    }
    const isFlutterSourceRoot = profile.archetype === "mobile-app" && parts[0] === "lib" && lower.endsWith(".dart");
    if (!isFlutterSourceRoot && parts.some((p) => p === "utils" || p === "util" || p === "helpers" || p === "helper" || p === "shared" || p === "common" || p === "lib" || p === "libs")) {
      return { source: "path", role: "shared", confidence: 0.8, reason: "Matched shared/utilities folder" };
    }
    if (profile.archetype === "cli-tool" || profile.archetype === "library") {
      if (parts.some((p) => p === "cli" || p === "bin" || p === "commands" || p === "cmd") || basename === "cli.ts" || basename === "cli.js" || basename === "main.ts" || basename === "main.js") {
        return { source: "path", role: "cli", confidence: 0.9, reason: "CLI/Entry point folder or file" };
      }
      if (parts.some((p) => p === "parsers" || p === "parser" || p === "languages" || p === "language") || basename.includes("parser")) {
        return { source: "path", role: "parsers", confidence: 0.9, reason: "Parser or language folder" };
      }
      if (parts.some((p) => p === "plugins" || p === "plugin" || p === "adapters" || p === "adapter")) {
        return { source: "path", role: "plugins", confidence: 0.9, reason: "Plugins/adapters folder" };
      }
      if (parts.some((p) => p === "core" || p === "domain" || p === "engine")) {
        return { source: "path", role: "core", confidence: 0.85, reason: "Core core engine folder" };
      }
    }
    if (profile.hasBackend) {
      if (parts.some((p) => p === "api" || p === "routes" || p === "controllers" || p === "controller" || p === "endpoints" || p === "handlers")) {
        return { source: "path", role: "api", confidence: 0.9, reason: "Backend route/controller API directory" };
      }
      if (parts.some((p) => p === "middleware" || p === "middlewares" || p === "guards" || p === "interceptors")) {
        return { source: "path", role: "middleware", confidence: 0.9, reason: "Request middleware/guards directory" };
      }
      if (parts.some((p) => p === "services" || p === "service" || p === "usecases" || p === "usecase" || p === "domain" || p === "logic")) {
        return { source: "path", role: "service", confidence: 0.85, reason: "Business logic/service directory" };
      }
      if (parts.some((p) => p === "stores" || p === "db" || p === "database" || p === "models" || p === "model" || p === "repositories" || p === "repository" || p === "migrations" || p === "seeds" || p === "data")) {
        return { source: "path", role: "data", confidence: 0.9, reason: "Persistence/database data directory" };
      }
      if (parts.some((p) => p === "auth" || p === "identity" || p === "login")) {
        return { source: "path", role: "auth", confidence: 0.9, reason: "Auth/identity directory" };
      }
      if (parts.some((p) => p === "integration" || p === "clients" || p === "external" || p === "sdk")) {
        return { source: "path", role: "integration", confidence: 0.85, reason: "Integration/external SDK client directory" };
      }
    }
    if (profile.hasFrontend) {
      if (parts.some((p) => p === "pages" || p === "screens" || p === "views")) {
        return { source: "path", role: "pages", confidence: 0.9, reason: "Frontend pages view directory" };
      }
      if (parts.some((p) => p === "components" || p === "widgets" || p === "ui" || p === "layout")) {
        return { source: "path", role: "components", confidence: 0.9, reason: "Frontend component UI directory" };
      }
      if (parts.some((p) => p === "store" || p === "stores" || p === "state" || p === "reducers" || p === "actions")) {
        return { source: "path", role: "state", confidence: 0.9, reason: "State management store directory" };
      }
      if (parts.some((p) => p === "hooks" || p === "composables")) {
        return { source: "path", role: "hooks", confidence: 0.9, reason: "React custom hooks/Vue composables directory" };
      }
      if (parts.some((p) => p === "styles" || p === "theme" || p === "css" || p === "sass" || p === "scss") || lower.endsWith(".css") || lower.endsWith(".scss")) {
        return { source: "path", role: "styles", confidence: 0.9, reason: "Styling stylesheet directory or file" };
      }
      if (parts.some((p) => p === "assets" || p === "images" || p === "fonts" || p === "icons" || p === "public")) {
        return { source: "path", role: "assets", confidence: 0.85, reason: "Frontend static assets directory" };
      }
      if (parts.some((p) => p === "blocs" || p === "bloc" || p === "cubits" || p === "cubit")) {
        return { source: "path", role: "state", confidence: 0.92, reason: "Flutter BLoC/Cubit state management directory" };
      }
      if (parts.some((p) => p === "providers" || p === "provider" || p === "notifiers" || p === "notifier")) {
        return { source: "path", role: "state", confidence: 0.9, reason: "Flutter Provider/Riverpod state directory" };
      }
      if (parts.some((p) => p === "controllers" || p === "controller") && lower.endsWith(".dart")) {
        return { source: "path", role: "state", confidence: 0.85, reason: "Flutter GetX controller directory" };
      }
      if (parts.some((p) => p === "repositories" || p === "repository" || p === "datasources" || p === "datasource")) {
        return { source: "path", role: "data", confidence: 0.9, reason: "Flutter data/repository layer directory" };
      }
      if (parts.some((p) => p === "models" || p === "model" || p === "entities" || p === "entity") && lower.endsWith(".dart")) {
        return { source: "path", role: "data", confidence: 0.85, reason: "Flutter data model/entity directory" };
      }
      if (parts.some((p) => p === "routes" || p === "router" || p === "navigation") && lower.endsWith(".dart")) {
        return { source: "path", role: "api", confidence: 0.88, reason: "Flutter routing/navigation directory" };
      }
    }
    if (basename === "main.ts" || basename === "main.js" || basename === "main.dart" || basename === "index.ts" || basename === "index.js" || basename === "app.ts" || basename === "app.js") {
      return { source: "path", role: "entry", confidence: 0.8, reason: "Entry point filename" };
    }
    return null;
  }
  getNamingSignal(filePath) {
    const symbols = this.store.getSymbolsForFile(filePath);
    if (symbols.length === 0) return null;
    const roleScores = {};
    const matches = [];
    for (const sym of symbols) {
      const name = sym.name;
      if (name.endsWith("Controller") || name.endsWith("Handler") || name.endsWith("Resolver")) {
        roleScores["api"] = (roleScores["api"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Service") || name.endsWith("UseCase") || name.endsWith("Interactor")) {
        roleScores["service"] = (roleScores["service"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Repository") || name.endsWith("DAO") || name.endsWith("Store") || name.endsWith("Model") || name.endsWith("Entity") || name.endsWith("Schema")) {
        roleScores["data"] = (roleScores["data"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Middleware") || name.endsWith("Guard") || name.endsWith("Interceptor")) {
        roleScores["middleware"] = (roleScores["middleware"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Component") || name.endsWith("Widget") || name.endsWith("View") || name.endsWith("Screen") || name.endsWith("Page")) {
        roleScores["components"] = (roleScores["components"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Bloc") || name.endsWith("Cubit") || name.endsWith("Notifier") || name.endsWith("ChangeNotifier") || name.endsWith("Provider")) {
        roleScores["state"] = (roleScores["state"] || 0) + 1;
        matches.push(name);
      } else if (name.startsWith("use") && sym.kind === "function") {
        roleScores["hooks"] = (roleScores["hooks"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Dto") || name.endsWith("Type") || name.endsWith("Interface") || name.endsWith("Props")) {
        roleScores["types"] = (roleScores["types"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Test") || name.endsWith("Spec")) {
        roleScores["test"] = (roleScores["test"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Config") || name.endsWith("Options")) {
        roleScores["config"] = (roleScores["config"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Util") || name.endsWith("Helper")) {
        roleScores["shared"] = (roleScores["shared"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Parser")) {
        roleScores["parsers"] = (roleScores["parsers"] || 0) + 1;
        matches.push(name);
      } else if (name.endsWith("Plugin") || name.endsWith("Adapter")) {
        roleScores["plugins"] = (roleScores["plugins"] || 0) + 1;
        matches.push(name);
      }
    }
    const bestRoleEntry = Object.entries(roleScores).sort((a, b) => b[1] - a[1])[0];
    if (!bestRoleEntry) return null;
    const matchedRole = bestRoleEntry[0];
    return {
      source: "naming",
      role: matchedRole,
      confidence: 0.8,
      reason: `Exports symbols with standard role suffixes: ${matches.slice(0, 3).join(", ")}`
    };
  }
  getTopologySignal(filePath, profile) {
    const inEdges = this.store.raw.prepare("SELECT COUNT(*) as count FROM edges WHERE target_file = ?").get(filePath);
    const outEdges = this.store.raw.prepare("SELECT COUNT(*) as count FROM edges WHERE source_file = ?").get(filePath);
    const fanIn = inEdges?.count || 0;
    const fanOut = outEdges?.count || 0;
    if (fanIn === 0 && fanOut > 0) {
      const suggestedRole = profile.hasBackend ? "api" : "entry";
      return {
        source: "topology",
        role: suggestedRole,
        confidence: 0.7,
        reason: `Zero fan-in and non-zero fan-out (${fanOut}) suggests routing or CLI entry point`
      };
    }
    if (fanIn > 10 && fanOut === 0) {
      const ext = path.extname(filePath).toLowerCase();
      const suggestedRole = ext === ".d.ts" || ext === ".types" ? "types" : "shared";
      return {
        source: "topology",
        role: suggestedRole,
        confidence: 0.7,
        reason: `High fan-in (${fanIn}) and zero fan-out suggests shared utility or types leaf`
      };
    }
    return null;
  }
  getFrameworkSignal(filePath, routes, hooks) {
    const lower = filePath.toLowerCase();
    const isRouter = routes.some((r) => r.handlerFile === filePath || r.metadata && r.metadata.sourceFile === filePath);
    if (isRouter) {
      return {
        source: "framework",
        role: "api",
        confidence: 0.9,
        reason: "Registered as a controller or handler in framework route bindings"
      };
    }
    const isHook = hooks.some((h) => h.handlerFile === filePath);
    if (isHook) {
      return {
        source: "framework",
        role: "middleware",
        confidence: 0.85,
        reason: "Registered in framework hook bindings"
      };
    }
    return null;
  }
  getImportsSignal(filePath) {
    const rows = this.backendQueryImports(filePath);
    if (rows.length === 0) return null;
    const roleScores = {};
    for (const r of rows) {
      const target = r.target_file.toLowerCase();
      if (target.includes("express") || target.includes("koa") || target.includes("fastify") || target.includes("@nestjs/common")) {
        roleScores["api"] = (roleScores["api"] || 0) + 1;
      } else if (target.includes("sequelize") || target.includes("typeorm") || target.includes("prisma") || target.includes("mongoose")) {
        roleScores["data"] = (roleScores["data"] || 0) + 1;
      } else if (target.includes("react") || target.includes("vue") || target.includes("svelte") || target.includes("@angular")) {
        roleScores["components"] = (roleScores["components"] || 0) + 1;
      } else if (target.includes("redux") || target.includes("vuex") || target.includes("pinia") || target.includes("zustand")) {
        roleScores["state"] = (roleScores["state"] || 0) + 1;
      } else if (target.includes("vitest") || target.includes("jest") || target.includes("mocha") || target.includes("chai")) {
        roleScores["test"] = (roleScores["test"] || 0) + 1;
      } else if (target.includes("flutter_bloc") || target.includes("bloc/") || target.includes("riverpod") || target.includes("provider")) {
        roleScores["state"] = (roleScores["state"] || 0) + 1;
      } else if (target.includes("flutter/material") || target.includes("flutter/cupertino") || target.includes("flutter/widgets")) {
        roleScores["components"] = (roleScores["components"] || 0) + 1;
      } else if (target.includes("sqflite") || target.includes("hive") || target.includes("drift") || target.includes("isar")) {
        roleScores["data"] = (roleScores["data"] || 0) + 1;
      }
    }
    const bestRoleEntry = Object.entries(roleScores).sort((a, b) => b[1] - a[1])[0];
    if (!bestRoleEntry) return null;
    const matchedRole = bestRoleEntry[0];
    return {
      source: "imports",
      role: matchedRole,
      confidence: 0.75,
      reason: `Imports library associated with ${matchedRole} role`
    };
  }
  backendQueryImports(filePath) {
    try {
      return this.store.raw.prepare(`
        SELECT target_file FROM edges
        WHERE source_file = ? AND (edge_type = 'import' OR edge_type = 'require')
      `).all(filePath);
    } catch {
      return [];
    }
  }
}
export {
  RoleClassifier
};
