import { describe, it, expect, vi, beforeEach } from "vitest";
import { prismaMock, resetPrismaMock } from "@/__tests__/helpers/prisma-mock";
import { createRequest, parseJsonResponse } from "@/__tests__/helpers/api-test-utils";

vi.mock("@/lib/auth", () => ({
  getAuthUserId: vi.fn().mockResolvedValue("user-1"),
}));

vi.mock("@/lib/blindbox", () => ({
  requireMembership: vi.fn().mockResolvedValue({}),
}));

import { POST } from "./route";

const mockCtx = { params: Promise.resolve({}) };

beforeEach(() => {
  resetPrismaMock();
});

describe("POST /api/blindbox/draw", () => {
  it("draws a random idea", async () => {
    prismaMock.$transaction.mockImplementation((async (fn: unknown) => {
      const tx = {
        blindBoxIdea: {
          findMany: vi.fn().mockResolvedValue([{ id: "idea-1" }]),
          updateMany: vi.fn().mockResolvedValue({ count: 1 }),
          findUnique: vi.fn().mockResolvedValue({
            id: "idea-1",
            content: "去公园",
            createdAt: new Date(),
            user: { id: "user-2", username: "submitter", avatar: "🐶" },
            drawnBy: { id: "user-1", username: "drawer", avatar: "🐱" },
          }),
        },
      };
      return (fn as (txArg: typeof tx) => Promise<unknown>)(tx);
    }) as never);

    const req = createRequest("/api/blindbox/draw", {
      method: "POST",
      body: { roomId: "bb-room-1" },
    });
    const res = await POST(req, mockCtx);
    const { status, data } = await parseJsonResponse(res);

    expect(status).toBe(200);
    expect(data.id).toBe("idea-1");
    expect(data.content).toBe("去公园");
    expect(data.submitter).toBeDefined();
    expect(data.drawnBy).toBeDefined();
  });

  it("returns 404 when pool is empty", async () => {
    prismaMock.$transaction.mockImplementation((async (fn: unknown) => {
      const tx = {
        blindBoxIdea: {
          findMany: vi.fn().mockResolvedValue([]),
          updateMany: vi.fn(),
          findUnique: vi.fn(),
        },
      };
      return (fn as (txArg: typeof tx) => Promise<unknown>)(tx);
    }) as never);

    const req = createRequest("/api/blindbox/draw", {
      method: "POST",
      body: { roomId: "bb-room-1" },
    });
    const res = await POST(req, mockCtx);
    expect(res.status).toBe(404);
  });

  it("returns 409 on race condition (count=0)", async () => {
    prismaMock.$transaction.mockImplementation((async (fn: unknown) => {
      const tx = {
        blindBoxIdea: {
          findMany: vi.fn().mockResolvedValue([{ id: "idea-1" }]),
          updateMany: vi.fn().mockResolvedValue({ count: 0 }),
          findUnique: vi.fn(),
        },
      };
      return (fn as (txArg: typeof tx) => Promise<unknown>)(tx);
    }) as never);

    const req = createRequest("/api/blindbox/draw", {
      method: "POST",
      body: { roomId: "bb-room-1" },
    });
    const res = await POST(req, mockCtx);
    expect(res.status).toBe(409);
  });

  it("returns 400 when roomId is missing", async () => {
    const req = createRequest("/api/blindbox/draw", {
      method: "POST",
      body: {},
    });
    const res = await POST(req, mockCtx);
    expect(res.status).toBe(400);
  });
});
