import { describe, it, expect, vi, beforeEach } from "vitest";
import { searchModuleDocs, formatSearchResults, runDocSearch } from "./search";

describe("searchModuleDocs", () => {
  it("returns results for known content", () => {
    const results = searchModuleDocs("Organization module");
    expect(results.length).toBeGreaterThan(0);
    const orgResults = results.filter((r) => r.module === "organization");
    expect(orgResults.length).toBeGreaterThan(0);
  });

  it("is case-insensitive", () => {
    const lower = searchModuleDocs("organization module");
    const upper = searchModuleDocs("ORGANIZATION MODULE");
    expect(lower.length).toBe(upper.length);
    expect(lower.length).toBeGreaterThan(0);
  });

  it("filters by doc type", () => {
    const readmeOnly = searchModuleDocs("Organization module", "readme");
    expect(readmeOnly.length).toBeGreaterThan(0);
    for (const r of readmeOnly) {
      expect(r.type).toBe("readme");
    }
  });

  it("returns empty array for no matches", () => {
    const results = searchModuleDocs("xyzzy_nonexistent_term_12345");
    expect(results).toEqual([]);
  });

  it("includes line numbers", () => {
    const results = searchModuleDocs("Organization module");
    for (const r of results) {
      expect(r.line).toBeGreaterThan(0);
    }
  });
});

describe("formatSearchResults", () => {
  it("formats results with module/type/name", () => {
    const output = formatSearchResults([
      { module: "org", type: "command", name: "Create", line: 5, excerpt: "Create an org" },
    ]);
    expect(output).toContain("org/command/Create:5: Create an org");
    expect(output).toContain("1 matches");
  });

  it("handles empty results", () => {
    expect(formatSearchResults([])).toBe("No results found.");
  });
});

describe("runDocSearch", () => {
  beforeEach(() => {
    vi.restoreAllMocks();
  });

  it("outputs valid JSON with --format json", () => {
    const logs: string[] = [];
    vi.spyOn(console, "log").mockImplementation((...args: unknown[]) => {
      logs.push(args.map(String).join(" "));
    });

    const { exitCode } = runDocSearch("Organization module", undefined, "json");
    expect(exitCode).toBe(0);

    const parsed = JSON.parse(logs.join("\n")) as unknown[];
    expect(Array.isArray(parsed)).toBe(true);
    expect(parsed.length).toBeGreaterThan(0);
  });

  it("returns exit code 1 for invalid type", () => {
    const errors: string[] = [];
    vi.spyOn(console, "error").mockImplementation((...args: unknown[]) => {
      errors.push(args.map(String).join(" "));
    });

    const { exitCode } = runDocSearch("test", "invalid");
    expect(exitCode).toBe(1);
    expect(errors[0]).toContain("Unknown doc type");
  });

  it("outputs 'No results found' for no matches in text mode", () => {
    const logs: string[] = [];
    vi.spyOn(console, "log").mockImplementation((...args: unknown[]) => {
      logs.push(args.map(String).join(" "));
    });

    const { exitCode } = runDocSearch("xyzzy_nonexistent_12345");
    expect(exitCode).toBe(0);
    expect(logs.join("\n")).toContain("No results found.");
  });
});
