import { describe, expect, test } from "bun:test";
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { buildRouter } from "../src/index.ts";

const root = join(import.meta.dir, ".tmp-services");
mkdirSync(root, { recursive: true });

function makeApp(): string {
  const base = mkdtempSync(join(root, "app-"));
  mkdirSync(join(base, "app", "pages"), { recursive: true });
  return join(base, "app");
}

describe("service discovery", () => {
  test("discovers source services and skips generated files", () => {
    const appDir = makeApp();
    const services = join(appDir, "services");
    mkdirSync(services, { recursive: true });
    writeFileSync(join(services, "billing.ts"), "export default {};");
    writeFileSync(join(services, "types.gen.ts"), "export type T = string;");
    expect(buildRouter(appDir).services.map((service) => service.name)).toEqual(["billing"]);
  });

  test("throws naming both files when two services collide on name", () => {
    const appDir = makeApp();
    const services = join(appDir, "services");
    const nested = join(services, "legacy");
    mkdirSync(nested, { recursive: true });
    const top = join(services, "billing.ts");
    const shadow = join(nested, "billing.ts");
    writeFileSync(top, "export default {};");
    writeFileSync(shadow, "export default {};");
    expect(() => buildRouter(appDir)).toThrow(/WRN-SERVICE-COLLISION/);
    try {
      buildRouter(appDir);
    } catch (error) {
      const message = (error as Error).message;
      expect(message).toContain(top);
      expect(message).toContain(shadow);
    }
  });

  test("unsafe service names are skipped with a warning", () => {
    const appDir = makeApp();
    const services = join(appDir, "services");
    mkdirSync(services, { recursive: true });
    writeFileSync(join(services, "bad name.ts"), "export default {};");
    const originalWarn = console.warn;
    let warned = false;
    console.warn = (...args: unknown[]) => {
      if (String(args[0]).includes("skipping service with unsafe name")) warned = true;
    };
    try {
      expect(buildRouter(appDir).services).toEqual([]);
      expect(warned).toBe(true);
    } finally {
      console.warn = originalWarn;
    }
  });

  test("a missing services directory yields []", () => {
    const appDir = makeApp();
    expect(buildRouter(appDir).services).toEqual([]);
  });

  test("discovers .js service files", () => {
    const appDir = makeApp();
    const services = join(appDir, "services");
    mkdirSync(services, { recursive: true });
    writeFileSync(join(services, "reports.js"), "export default {};");
    expect(buildRouter(appDir).services.map((service) => service.name)).toEqual(["reports"]);
  });
});
