import { describe, test, expect } from "bun:test";
import { Hono } from "hono";
import { validateWebhookPayload } from "@/server/middleware/validate.js";

function validPayload() {
  return {
    webhookEvent: "jira:issue_updated",
    issue: {
      id: "10001",
      key: "HU-42",
      fields: {
        issuetype: { name: "Bug" },
        status: { name: "To Do" },
        summary: "Login page error",
        description: null,
      },
    },
  };
}

function createApp() {
  const app = new Hono();
  app.post("/webhook", validateWebhookPayload, (c) => {
    return c.json({ ok: true });
  });
  return app;
}

describe("validateWebhookPayload", () => {
  test("valid webhook payload passes through to handler and returns 200", async () => {
    const app = createApp();
    const res = await app.request("/webhook", {
      method: "POST",
      body: JSON.stringify(validPayload()),
      headers: { "Content-Type": "application/json" },
    });
    expect(res.status).toBe(200);
    const body = (await res.json()) as Record<string, unknown>;
    expect(body).toEqual({ ok: true });
  });

  test("empty body returns 400 with Invalid JSON body", async () => {
    const app = createApp();
    const res = await app.request("/webhook", {
      method: "POST",
      body: "",
      headers: { "Content-Type": "application/json" },
    });
    expect(res.status).toBe(400);
    const body = (await res.json()) as Record<string, unknown>;
    expect(body).toEqual({ error: "Invalid JSON body" });
  });

  test("missing required field returns 400 with validation details", async () => {
    const app = createApp();
    const payload = { webhookEvent: "jira:issue_created" };
    const res = await app.request("/webhook", {
      method: "POST",
      body: JSON.stringify(payload),
      headers: { "Content-Type": "application/json" },
    });
    expect(res.status).toBe(400);
    const body = (await res.json()) as {
      error: string;
      details: Array<{ path: string; message: string }>;
    };
    expect(body.error).toBe("Invalid webhook payload");
    expect(Array.isArray(body.details)).toBe(true);
    expect(body.details.length).toBeGreaterThan(0);
    expect(body.details[0]).toHaveProperty("path");
    expect(body.details[0]).toHaveProperty("message");
  });

  test("non-JSON body (plain text) returns 400 with Invalid JSON body", async () => {
    const app = createApp();
    const res = await app.request("/webhook", {
      method: "POST",
      body: "this is not json",
      headers: { "Content-Type": "text/plain" },
    });
    expect(res.status).toBe(400);
    const body = (await res.json()) as Record<string, unknown>;
    expect(body).toEqual({ error: "Invalid JSON body" });
  });

  test("malformed JSON returns 400 with Invalid JSON body", async () => {
    const app = createApp();
    const res = await app.request("/webhook", {
      method: "POST",
      body: '{ "webhookEvent": "jira:issue_created", ',
      headers: { "Content-Type": "application/json" },
    });
    expect(res.status).toBe(400);
    const body = (await res.json()) as Record<string, unknown>;
    expect(body).toEqual({ error: "Invalid JSON body" });
  });
});
