import { describe, test, expect } from "bun:test";
import { resolve } from "node:path";
import { RepoRegistry } from "@/repo/registry.js";

const FIXTURES = resolve(import.meta.dir, "fixtures");
const VALID_PATH = resolve(FIXTURES, "valid-repos.json");
const INVALID_PATH = resolve(FIXTURES, "invalid-repos.json");
const MALFORMED_PATH = resolve(FIXTURES, "malformed.json");
const MISSING_PATH = resolve(FIXTURES, "does-not-exist.json");
const REAL_REPOS_PATH = resolve(import.meta.dir, "../../repos.json");

// ── Construction with valid fixture ──────────────────────────────────────────

describe("RepoRegistry — valid fixture", () => {
  const registry = new RepoRegistry(VALID_PATH);

  test("getAll returns the two repos from the fixture", () => {
    const all = registry.getAll();
    expect(all).toHaveLength(2);
  });

  test("getAll returns repos with correct names", () => {
    const names = registry.getAll().map((r) => r.name);
    expect(names).toEqual(["api", "web"]);
  });

  test("getAll returns readonly array (same reference on repeat calls)", () => {
    const first = registry.getAll();
    const second = registry.getAll();
    expect(first).toBe(second);
  });
});

// ── getByName ────────────────────────────────────────────────────────────────

describe("RepoRegistry — getByName", () => {
  const registry = new RepoRegistry(VALID_PATH);

  test("returns the matching repo by name", () => {
    const repo = registry.getByName("api");
    expect(repo).toBeDefined();
    expect(repo!.name).toBe("api");
    expect(repo!.url).toBe("git@github.com:org/api.git");
    expect(repo!.description).toBe("Main API backend service");
    expect(repo!.keywords).toEqual(["api", "backend"]);
    expect(repo!.defaultBranch).toBe("develop");
  });

  test("returns undefined for a name that does not exist", () => {
    const repo = registry.getByName("nope");
    expect(repo).toBeUndefined();
  });
});

// ── Invalid fixture (Zod validation) ─────────────────────────────────────────

describe("RepoRegistry — invalid fixture", () => {
  test("throws a Zod validation error when required fields are missing", () => {
    expect(() => new RepoRegistry(INVALID_PATH)).toThrow();
  });
});

// ── Malformed JSON ───────────────────────────────────────────────────────────

describe("RepoRegistry — malformed JSON", () => {
  test("throws a SyntaxError when JSON is unparseable", () => {
    expect(() => new RepoRegistry(MALFORMED_PATH)).toThrow(SyntaxError);
  });
});

// ── Missing file ─────────────────────────────────────────────────────────────

describe("RepoRegistry — missing file", () => {
  test("throws when the config file does not exist", () => {
    expect(() => new RepoRegistry(MISSING_PATH)).toThrow();
  });
});

// ── Smoke: real repos.json ───────────────────────────────────────────────────

describe("RepoRegistry — real repos.json smoke test", () => {
  test("parses the project root repos.json without error", () => {
    const registry = new RepoRegistry(REAL_REPOS_PATH);
    const all = registry.getAll();
    expect(all.length).toBeGreaterThan(0);
  });
});
