import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { logger } from "../../../core/monitoring/logger.js";
import { execSync } from "child_process";
import { existsSync, readFileSync } from "fs";
import { join } from "path";
class DiscoveryHandlers {
  constructor(deps) {
    this.deps = deps;
  }
  /**
   * Discover relevant files based on current context
   */
  async handleDiscover(args) {
    try {
      const {
        query,
        depth = "medium",
        includePatterns = ["*.ts", "*.tsx", "*.js", "*.md", "*.json"],
        excludePatterns = ["node_modules", "dist", ".git", "*.min.js"],
        maxFiles = 20
      } = args;
      logger.info("Starting discovery", { query, depth });
      const keywords = this.extractContextKeywords(query);
      const mdContext = this.parseMdFiles();
      const recentFiles = this.getRecentFilesFromContext();
      const discoveredFiles = await this.searchCodebase(
        keywords,
        includePatterns,
        excludePatterns,
        depth,
        maxFiles
      );
      const rankedFiles = this.rankFiles(
        discoveredFiles,
        recentFiles,
        keywords
      );
      const contextSummary = this.generateContextSummary(keywords, rankedFiles);
      const result = {
        files: rankedFiles.slice(0, maxFiles),
        keywords,
        contextSummary,
        mdContext
      };
      return {
        content: [
          {
            type: "text",
            text: this.formatDiscoveryResult(result)
          }
        ],
        metadata: result
      };
    } catch (error) {
      logger.error("Discovery failed", error);
      throw error;
    }
  }
  /**
   * Get related files to a specific file or concept
   */
  async handleRelatedFiles(args) {
    try {
      const { file, concept, maxFiles = 10 } = args;
      if (!file && !concept) {
        throw new Error("Either file or concept is required");
      }
      let relatedFiles = [];
      if (file) {
        relatedFiles = this.findFileReferences(file, maxFiles);
      }
      if (concept) {
        const conceptFiles = this.searchForConcept(concept, maxFiles);
        relatedFiles = this.mergeAndDedupe(relatedFiles, conceptFiles);
      }
      return {
        content: [
          {
            type: "text",
            text: this.formatRelatedFiles(relatedFiles, file, concept)
          }
        ],
        metadata: { relatedFiles }
      };
    } catch (error) {
      logger.error("Related files search failed", error);
      throw error;
    }
  }
  /**
   * Get session summary with actionable context
   */
  async handleSessionSummary(args) {
    try {
      const { includeFiles = true, includeDecisions = true } = args;
      const hotStack = this.deps.frameManager.getHotStackContext(50);
      const recentFiles = includeFiles ? this.getRecentFilesFromContext() : [];
      const decisions = includeDecisions ? this.getRecentDecisions() : [];
      const summary = {
        activeFrames: hotStack.length,
        currentGoal: hotStack[hotStack.length - 1]?.header?.goal || "No active task",
        recentFiles: recentFiles.slice(0, 10),
        decisions: decisions.slice(0, 5),
        stackDepth: this.deps.frameManager.getStackDepth()
      };
      return {
        content: [
          {
            type: "text",
            text: this.formatSessionSummary(summary)
          }
        ],
        metadata: summary
      };
    } catch (error) {
      logger.error("Session summary failed", error);
      throw error;
    }
  }
  // ===============================
  // Private helper methods
  // ===============================
  extractContextKeywords(query) {
    const keywords = /* @__PURE__ */ new Set();
    if (query) {
      const queryWords = query.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
      queryWords.forEach((w) => keywords.add(w));
    }
    const hotStack = this.deps.frameManager.getHotStackContext(20);
    for (const frame of hotStack) {
      if (frame.header?.goal) {
        const goalWords = frame.header.goal.toLowerCase().split(/[\s\-_]+/).filter((w) => w.length > 2);
        goalWords.forEach((w) => keywords.add(w));
      }
      frame.header?.constraints?.forEach((c) => {
        const words = c.toLowerCase().split(/[\s\-_]+/).filter((w) => w.length > 2);
        words.forEach((w) => keywords.add(w));
      });
      frame.recentEvents?.forEach((evt) => {
        if (evt.data?.content) {
          const words = String(evt.data.content).toLowerCase().split(/[\s\-_]+/).filter((w) => w.length > 3).slice(0, 5);
          words.forEach((w) => keywords.add(w));
        }
      });
    }
    try {
      const fileEvents = this.deps.db.prepare(
        `
        SELECT DISTINCT data FROM events e
        JOIN frames f ON e.frame_id = f.frame_id
        WHERE e.type IN ('file_read', 'file_write', 'file_edit')
        ORDER BY e.timestamp DESC
        LIMIT 20
      `
      ).all();
      for (const evt of fileEvents) {
        try {
          const data = JSON.parse(evt.data || "{}");
          if (data.path) {
            const pathParts = data.path.split("/").slice(-2);
            pathParts.forEach((part) => {
              const words = part.replace(/\.[^.]+$/, "").split(/[\-_]+/).filter((w) => w.length > 2);
              words.forEach((w) => keywords.add(w.toLowerCase()));
            });
          }
        } catch {
        }
      }
    } catch {
    }
    const stopwords = /* @__PURE__ */ new Set([
      "the",
      "and",
      "for",
      "with",
      "this",
      "that",
      "from",
      "have",
      "has",
      "been",
      "will",
      "can",
      "should",
      "would",
      "could",
      "function",
      "const",
      "let",
      "var",
      "import",
      "export",
      "return",
      "async",
      "await"
    ]);
    return Array.from(keywords).filter((k) => !stopwords.has(k));
  }
  parseMdFiles() {
    const mdContext = {};
    const mdFiles = ["CLAUDE.md", "README.md", ".stackmemory/context.md"];
    for (const mdFile of mdFiles) {
      const fullPath = join(this.deps.projectRoot, mdFile);
      if (existsSync(fullPath)) {
        try {
          const content = readFileSync(fullPath, "utf8");
          const sections = this.extractMdSections(content);
          mdContext[mdFile] = sections;
        } catch {
        }
      }
    }
    const homeClaude = join(process.env["HOME"] || "", ".claude", "CLAUDE.md");
    if (existsSync(homeClaude)) {
      try {
        const content = readFileSync(homeClaude, "utf8");
        mdContext["~/.claude/CLAUDE.md"] = this.extractMdSections(content);
      } catch {
      }
    }
    return mdContext;
  }
  extractMdSections(content) {
    const lines = content.split("\n");
    const sections = [];
    let currentSection = "";
    let inCodeBlock = false;
    for (const line of lines) {
      if (line.startsWith("```")) {
        inCodeBlock = !inCodeBlock;
        continue;
      }
      if (inCodeBlock) continue;
      if (line.startsWith("#")) {
        if (currentSection) sections.push(currentSection.trim());
        currentSection = line + "\n";
      } else if (currentSection && line.trim()) {
        currentSection += line + "\n";
      }
    }
    if (currentSection) sections.push(currentSection.trim());
    return sections.map((s) => s.length > 500 ? s.slice(0, 500) + "..." : s).join("\n\n");
  }
  getRecentFilesFromContext() {
    const files = /* @__PURE__ */ new Set();
    try {
      const fileEvents = this.deps.db.prepare(
        `
        SELECT DISTINCT data FROM events e
        JOIN frames f ON e.frame_id = f.frame_id
        WHERE e.type IN ('file_read', 'file_write', 'file_edit', 'tool_call')
        AND e.timestamp > ?
        ORDER BY e.timestamp DESC
        LIMIT 50
      `
      ).all(Math.floor(Date.now() / 1e3) - 3600);
      for (const evt of fileEvents) {
        try {
          const data = JSON.parse(evt.data || "{}");
          if (data.path) files.add(data.path);
          if (data.file) files.add(data.file);
          if (data.file_path) files.add(data.file_path);
        } catch {
        }
      }
    } catch {
    }
    try {
      const gitStatus = execSync("git status --porcelain", {
        cwd: this.deps.projectRoot,
        encoding: "utf8"
      });
      const modifiedFiles = gitStatus.split("\n").filter((l) => l.trim()).map((l) => l.slice(3).trim()).filter((f) => f);
      modifiedFiles.forEach((f) => files.add(f));
    } catch {
    }
    return Array.from(files);
  }
  async searchCodebase(keywords, includePatterns, excludePatterns, depth, maxFiles) {
    const files = [];
    const maxResults = depth === "shallow" ? 10 : depth === "medium" ? 25 : 50;
    for (const keyword of keywords.slice(0, 10)) {
      try {
        const excludeArgs = excludePatterns.map((p) => `--exclude-dir=${p}`).join(" ");
        const includeArgs = includePatterns.map((p) => `--include=${p}`).join(" ");
        const cmd = `grep -ril ${excludeArgs} ${includeArgs} "${keyword}" . 2>/dev/null | head -${maxResults}`;
        const result = execSync(cmd, {
          cwd: this.deps.projectRoot,
          encoding: "utf8",
          timeout: 5e3
        });
        const matchedFiles = result.split("\n").filter((f) => f.trim());
        for (const file of matchedFiles) {
          const cleanPath = file.replace(/^\.\//, "");
          const existing = files.find((f) => f.path === cleanPath);
          if (existing) {
            existing.matchedKeywords = existing.matchedKeywords || [];
            if (!existing.matchedKeywords.includes(keyword)) {
              existing.matchedKeywords.push(keyword);
            }
          } else {
            files.push({
              path: cleanPath,
              relevance: "medium",
              reason: `Contains keyword: ${keyword}`,
              matchedKeywords: [keyword]
            });
          }
        }
      } catch {
      }
    }
    for (const file of files) {
      const matchCount = file.matchedKeywords?.length || 0;
      if (matchCount >= 3) {
        file.relevance = "high";
        file.reason = `Matches ${matchCount} keywords: ${file.matchedKeywords?.slice(0, 3).join(", ")}`;
      }
    }
    return files;
  }
  rankFiles(discovered, recent, keywords) {
    const recentSet = new Set(recent);
    for (const recentFile of recent) {
      const existing = discovered.find((f) => f.path === recentFile);
      if (existing) {
        existing.relevance = "high";
        existing.reason = "Recently accessed + " + existing.reason;
      } else {
        discovered.push({
          path: recentFile,
          relevance: "high",
          reason: "Recently accessed in context"
        });
      }
    }
    return discovered.sort((a, b) => {
      const relevanceOrder = { high: 3, medium: 2, low: 1 };
      const relDiff = relevanceOrder[b.relevance] - relevanceOrder[a.relevance];
      if (relDiff !== 0) return relDiff;
      const aMatches = a.matchedKeywords?.length || 0;
      const bMatches = b.matchedKeywords?.length || 0;
      return bMatches - aMatches;
    });
  }
  findFileReferences(file, maxFiles) {
    const results = [];
    try {
      const basename = file.replace(/\.[^.]+$/, "");
      const cmd = `grep -ril "from.*${basename}" . --include="*.ts" --include="*.tsx" --include="*.js" --exclude-dir=node_modules --exclude-dir=dist 2>/dev/null | head -${maxFiles}`;
      const result = execSync(cmd, {
        cwd: this.deps.projectRoot,
        encoding: "utf8",
        timeout: 5e3
      });
      const files = result.split("\n").filter((f) => f.trim());
      for (const f of files) {
        results.push({
          path: f.replace(/^\.\//, ""),
          relevance: "high",
          reason: `Imports ${file}`
        });
      }
    } catch {
    }
    return results;
  }
  searchForConcept(concept, maxFiles) {
    const results = [];
    try {
      const cmd = `grep -ril "${concept}" . --include="*.ts" --include="*.tsx" --include="*.md" --exclude-dir=node_modules --exclude-dir=dist 2>/dev/null | head -${maxFiles}`;
      const result = execSync(cmd, {
        cwd: this.deps.projectRoot,
        encoding: "utf8",
        timeout: 5e3
      });
      const files = result.split("\n").filter((f) => f.trim());
      for (const f of files) {
        results.push({
          path: f.replace(/^\.\//, ""),
          relevance: "medium",
          reason: `Contains "${concept}"`
        });
      }
    } catch {
    }
    return results;
  }
  mergeAndDedupe(a, b) {
    const pathSet = new Set(a.map((f) => f.path));
    const merged = [...a];
    for (const file of b) {
      if (!pathSet.has(file.path)) {
        merged.push(file);
        pathSet.add(file.path);
      }
    }
    return merged;
  }
  getRecentDecisions() {
    try {
      const decisions = this.deps.db.prepare(
        `
        SELECT a.text, a.type, a.priority, f.name as frame_name, a.created_at
        FROM anchors a
        JOIN frames f ON a.frame_id = f.frame_id
        WHERE a.type IN ('DECISION', 'CONSTRAINT', 'FACT')
        ORDER BY a.created_at DESC
        LIMIT 10
      `
      ).all();
      return decisions;
    } catch {
      return [];
    }
  }
  generateContextSummary(keywords, files) {
    const hotStack = this.deps.frameManager.getHotStackContext(5);
    const currentGoal = hotStack[hotStack.length - 1]?.header?.goal;
    let summary = "";
    if (currentGoal) {
      summary += `Current task: ${currentGoal}
`;
    }
    summary += `Context keywords: ${keywords.slice(0, 10).join(", ")}
`;
    summary += `Relevant files found: ${files.length}
`;
    summary += `High relevance: ${files.filter((f) => f.relevance === "high").length}`;
    return summary;
  }
  formatDiscoveryResult(result) {
    let output = "# Discovery Results\n\n";
    output += "## Context Summary\n";
    output += result.contextSummary + "\n\n";
    output += "## Relevant Files\n\n";
    for (const file of result.files.slice(0, 15)) {
      const icon = file.relevance === "high" ? "[HIGH]" : file.relevance === "medium" ? "[MED]" : "[LOW]";
      output += `${icon} ${file.path}
`;
      output += `      ${file.reason}
`;
    }
    if (result.keywords.length > 0) {
      output += "\n## Keywords Used\n";
      output += result.keywords.slice(0, 15).join(", ") + "\n";
    }
    return output;
  }
  formatRelatedFiles(files, file, concept) {
    let output = "# Related Files\n\n";
    if (file) output += `Related to file: ${file}
`;
    if (concept) output += `Related to concept: ${concept}
`;
    output += "\n";
    for (const f of files) {
      output += `- ${f.path}
  ${f.reason}
`;
    }
    return output;
  }
  formatSessionSummary(summary) {
    let output = "# Session Summary\n\n";
    output += `**Current Goal:** ${summary.currentGoal}
`;
    output += `**Active Frames:** ${summary.activeFrames}
`;
    output += `**Stack Depth:** ${summary.stackDepth}

`;
    if (summary.recentFiles.length > 0) {
      output += "## Recent Files\n";
      for (const f of summary.recentFiles) {
        output += `- ${f}
`;
      }
      output += "\n";
    }
    if (summary.decisions.length > 0) {
      output += "## Recent Decisions\n";
      for (const d of summary.decisions) {
        output += `- [${d.type}] ${d.text}
`;
      }
    }
    return output;
  }
}
export {
  DiscoveryHandlers
};
//# sourceMappingURL=discovery-handlers.js.map
