import { readdirSync, readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
import { PACKAGE_ROOT } from "../../../util";
import { type CommandResult, success, silentFailure } from "../../lib/command-result";
import { MODULE_PATHS } from "../../lib/paths";

const MODULES_DIR = join(PACKAGE_ROOT, "src", "modules");

const DOC_TYPE_MAP: Record<string, string> = {
  command: MODULE_PATHS.docs.command,
  query: MODULE_PATHS.docs.query,
  model: MODULE_PATHS.docs.model,
  feature: MODULE_PATHS.docs.feature,
};

export interface SearchResult {
  module: string;
  type: string;
  name: string;
  line: number;
  excerpt: string;
}

function searchFile(
  filePath: string,
  query: string,
  module: string,
  type: string,
  name: string,
): SearchResult[] {
  if (!existsSync(filePath)) return [];
  const content = readFileSync(filePath, "utf-8");
  const lowerQuery = query.toLowerCase();
  const results: SearchResult[] = [];

  const lines = content.split("\n");
  for (let i = 0; i < lines.length; i++) {
    if (lines[i].toLowerCase().includes(lowerQuery)) {
      results.push({
        module,
        type,
        name,
        line: i + 1,
        excerpt: lines[i].trim(),
      });
    }
  }
  return results;
}

export function searchModuleDocs(query: string, typeFilter?: string): SearchResult[] {
  if (!existsSync(MODULES_DIR)) return [];

  const results: SearchResult[] = [];
  const modules = readdirSync(MODULES_DIR, { withFileTypes: true })
    .filter((d) => d.isDirectory())
    .sort((a, b) => a.name.localeCompare(b.name));

  for (const mod of modules) {
    const modDir = join(MODULES_DIR, mod.name);

    // Search README
    if (!typeFilter || typeFilter === "readme") {
      results.push(...searchFile(join(modDir, "README.md"), query, mod.name, "readme", "README"));
    }

    // Search doc type directories
    for (const [type, subdir] of Object.entries(DOC_TYPE_MAP)) {
      if (typeFilter && typeFilter !== type) continue;
      const docsDir = join(modDir, subdir);
      if (!existsSync(docsDir)) continue;

      const files = readdirSync(docsDir).filter((f) => f.endsWith(".md"));
      for (const file of files) {
        const name = file.replace(/\.md$/, "");
        results.push(...searchFile(join(docsDir, file), query, mod.name, type, name));
      }
    }
  }

  return results;
}

export function formatSearchResults(results: SearchResult[]): string {
  if (results.length === 0) return "No results found.";

  const lines: string[] = [];
  for (const r of results) {
    lines.push(`${r.module}/${r.type}/${r.name}:${r.line}: ${r.excerpt}`);
  }
  lines.push("");
  lines.push(`${results.length} matches`);
  return lines.join("\n");
}

export function runDocSearch(query: string, type?: string, format = "text"): CommandResult {
  if (type && type !== "readme" && !(type in DOC_TYPE_MAP)) {
    console.error(`Unknown doc type: ${type}`);
    console.error(`Available types: readme, ${Object.keys(DOC_TYPE_MAP).join(", ")}`);
    return silentFailure();
  }

  const results = searchModuleDocs(query, type);

  if (format === "json") {
    console.log(JSON.stringify(results, null, 2));
  } else {
    console.log(formatSearchResults(results));
  }
  return success();
}
