import { describe, it, expect, beforeAll, afterEach, afterAll } from "vitest";
import { POST } from "@/app/api/webhook/git/route";
import { prisma } from "@/lib/db";
import { eventBus, type PMEvent } from "@/lib/events/bus";

const TOKEN = "test-webhook-token-secret";

beforeAll(() => {
  process.env.PM_WEBHOOK_TOKEN = TOKEN;
});

afterEach(async () => {
  await prisma.commitLog.deleteMany({});
  await prisma.project.deleteMany({});
});

afterAll(async () => {
  await prisma.$disconnect();
});

function req(body: unknown, token = TOKEN): Request {
  return new Request("http://localhost/api/webhook/git", {
    method: "POST",
    headers: { "Content-Type": "application/json", "X-PM-Token": token },
    body: JSON.stringify(body),
  });
}

describe("POST /api/webhook/git", () => {
  it("rejects with 401 when token missing", async () => {
    const r = await POST(new Request("http://localhost/api/webhook/git", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({}),
    }));
    expect(r.status).toBe(401);
  });

  it("rejects with 401 on wrong token", async () => {
    const r = await POST(req({ project: "x", hash: "abc1234", message: "z", branch: "main" }, "bad"));
    expect(r.status).toBe(401);
  });

  it("returns 404 if project name not found", async () => {
    const r = await POST(req({ project: "ghost", hash: "0".repeat(40), message: "m", branch: "main" }));
    expect(r.status).toBe(404);
  });

  it("updates project + inserts CommitLog + emits events when valid", async () => {
    const p = await prisma.project.create({
      data: { name: "alpha", path: "/tmp/alpha", source: "manual" },
    });
    const events: PMEvent[] = [];
    const unsub = eventBus.subscribe((e) => events.push(e));

    const r = await POST(req({
      project: "alpha",
      hash: "a".repeat(40),
      message: "feat: hello",
      branch: "main",
      author: "tester",
    }));

    unsub();
    expect(r.status).toBe(200);
    const body = await r.json();
    expect(body.ok).toBe(true);

    const updated = await prisma.project.findUnique({ where: { id: p.id } });
    expect(updated?.lastCommitHash).toBe("a".repeat(40));
    expect(updated?.lastCommitMessage).toBe("feat: hello");
    expect(updated?.branch).toBe("main");

    const commits = await prisma.commitLog.findMany({ where: { projectId: p.id } });
    expect(commits).toHaveLength(1);
    expect(commits[0].author).toBe("tester");

    const types = events.map((e) => e.type);
    expect(types).toContain("commit.new");
    expect(types).toContain("project.updated");
  });
});
