/**
 * A new repository should arrive working, not empty.
 *
 * POST /new called bootstrapRepository(), which creates the DB side only —
 * gate settings, branch protection, labels, welcome issue. It created no git
 * content, so a new user landed on an EMPTY repository: no commit, no README,
 * no workflow, and therefore no CI run to be green. Every push-triggered
 * feature the product sells had nothing to act on, and the first thing a new
 * user saw was an empty state telling them to go and configure something.
 *
 * scaffoldFirstRepo seeds a README and a CI workflow, then calls the SAME
 * syncAndEnqueuePushWorkflows() seam the git post-receive hook calls. That
 * last step is the one that is easy to miss and impossible to notice: files
 * written through the plumbing API do not fire the git hook, so without it
 * the workflow sits on disk with no `workflows` row and no run — the repo
 * looks configured and does nothing.
 */

import { describe, expect, it } from "bun:test";
import { readFileSync } from "fs";

const SRC = readFileSync("src/lib/first-repo-scaffold.ts", "utf8");
const WEB = readFileSync("src/routes/web.tsx", "utf8");

describe("wiring", () => {
  it("POST /new scaffolds after bootstrapping", () => {
    const handler = WEB.slice(
      WEB.indexOf('web.post("/new"'),
      WEB.indexOf("// Daily brief")
    );
    expect(handler.length).toBeGreaterThan(200);
    expect(handler).toContain("bootstrapRepository");
    expect(handler).toContain("scaffoldFirstRepo");
    // Bootstrap first: the scaffold's CI run is gated by settings that
    // bootstrapRepository creates.
    expect(handler.indexOf("bootstrapRepository")).toBeLessThan(
      handler.indexOf("scaffoldFirstRepo")
    );
  });

  it("a scaffold failure cannot break repo creation", () => {
    const handler = WEB.slice(
      WEB.indexOf('web.post("/new"'),
      WEB.indexOf("// Daily brief")
    );
    const block = handler.slice(handler.indexOf("scaffoldFirstRepo") - 400);
    expect(block).toContain("catch");
  });

  it("uses the same sync seam as the post-receive hook", () => {
    // Writing via the plumbing API does not fire the git hook, so the
    // workflow would never be discovered without calling this directly.
    expect(SRC).toContain("syncAndEnqueuePushWorkflows");
    const hook = readFileSync("src/hooks/post-receive.ts", "utf8");
    expect(hook).toContain("syncAndEnqueuePushWorkflows");
  });
});

describe("what gets seeded", () => {
  it("writes a README and a CI workflow at the discovered path", () => {
    expect(SRC).toContain('"README.md"');
    // workflows.tsx documents .gluecron/workflows/ as the discovery dir;
    // a workflow written anywhere else is invisible.
    expect(SRC).toContain('".gluecron/workflows/ci.yml"');
  });

  it("the workflow triggers on push", () => {
    // syncAndEnqueuePushWorkflows only enqueues workflows whose `on:`
    // includes push — a workflow without it syncs but never runs.
    const wf = SRC.slice(SRC.indexOf("function ciWorkflow"), SRC.indexOf("function readme"));
    expect(wf).toMatch(/on:\s*\n\s*- push/);
  });

  it("the workflow has no external dependencies", () => {
    // It runs on a bare runner. The point is proving the pipeline works end
    // to end, not guessing the user's stack — anything needing a package
    // manager would fail and hand a new user a red X as their first result.
    const wf = SRC.slice(SRC.indexOf("function ciWorkflow"), SRC.indexOf("function readme"));
    expect(wf).not.toMatch(/npm |yarn |pnpm |bun install|pip |cargo /);
  });
});

describe("fault isolation", () => {
  const ok = async () => ({ commitSha: "abc", blobSha: "b", parentSha: null });
  const base = {
    owner: "alice",
    repoName: "demo",
    repositoryId: "r1",
    defaultBranch: "main",
    authorName: "alice",
    authorEmail: "a@b.c",
    userId: "u1",
  };

  it("reports a write failure instead of throwing", async () => {
    const { scaffoldFirstRepo } = await import("../lib/first-repo-scaffold");
    const r = await scaffoldFirstRepo(base, {
      createOrUpdateFileOnBranch: async () => ({ error: "write-failed" }),
      syncAndEnqueuePushWorkflows: async () => ({ synced: 0, enqueued: 0, errors: [] }),
    });
    expect(r.readmeCommitted).toBe(false);
    expect(r.workflowCommitted).toBe(false);
    expect(r.errors.join(" ")).toContain("write-failed");
  });

  it("does not attempt workflow sync when the workflow never committed", async () => {
    let syncCalled = false;
    const { scaffoldFirstRepo } = await import("../lib/first-repo-scaffold");
    const r = await scaffoldFirstRepo(base, {
      createOrUpdateFileOnBranch: async (i) =>
        i.filePath === "README.md" ? await ok() : { error: "write-failed" },
      syncAndEnqueuePushWorkflows: async () => {
        syncCalled = true;
        return { synced: 1, enqueued: 1, errors: [] };
      },
    });
    expect(r.readmeCommitted).toBe(true);
    expect(r.workflowCommitted).toBe(false);
    // Syncing a commit with no workflow in it would report a phantom run.
    expect(syncCalled).toBe(false);
    expect(r.runsEnqueued).toBe(0);
  });

  it("surfaces a sync failure without losing the commits", async () => {
    const { scaffoldFirstRepo } = await import("../lib/first-repo-scaffold");
    const r = await scaffoldFirstRepo(base, {
      createOrUpdateFileOnBranch: ok,
      syncAndEnqueuePushWorkflows: async () => {
        throw new Error("sync exploded");
      },
    });
    expect(r.readmeCommitted).toBe(true);
    expect(r.workflowCommitted).toBe(true);
    expect(r.errors.join(" ")).toContain("sync exploded");
  });

  it("reports the enqueued run on the happy path", async () => {
    const { scaffoldFirstRepo } = await import("../lib/first-repo-scaffold");
    const r = await scaffoldFirstRepo(base, {
      createOrUpdateFileOnBranch: ok,
      syncAndEnqueuePushWorkflows: async () => ({ synced: 1, enqueued: 1, errors: [] }),
    });
    expect(r.workflowsSynced).toBe(1);
    // This is the whole point: a green CI run with zero configuration.
    expect(r.runsEnqueued).toBe(1);
    expect(r.errors).toEqual([]);
  });
});
