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";
import { TEST_BLINDBOX_IDEA } from "@/__tests__/helpers/fixtures";
import { ApiError } from "@/lib/api";

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

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

vi.mock("@/lib/ai", () => ({
  tagIdea: vi.fn().mockResolvedValue({
    category: "outdoor",
    timeSlot: "morning",
    estimatedMinutes: 120,
    costLevel: "free",
    intensity: "active",
    needsBooking: false,
    searchQuery: "公园",
    searchType: "category",
  }),
}));

import { POST, GET, PUT, DELETE } from "./route";
import { getAuthUserId } from "@/lib/auth";

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

beforeEach(() => {
  resetPrismaMock();
  vi.mocked(getAuthUserId).mockResolvedValue("user-1");
});

describe("POST /api/blindbox (create idea)", () => {
  it("creates an idea successfully", async () => {
    prismaMock.blindBoxIdea.create.mockResolvedValue(TEST_BLINDBOX_IDEA as never);
    prismaMock.blindBoxIdea.update.mockResolvedValue(TEST_BLINDBOX_IDEA as never);

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

    expect(status).toBe(201);
    expect(data.id).toBe("idea-1");
  });

  it("returns 401 when not authenticated", async () => {
    vi.mocked(getAuthUserId).mockRejectedValueOnce(new ApiError("请先登录", 401));
    const req = createRequest("/api/blindbox", {
      method: "POST",
      body: { roomId: "bb-room-1", content: "test" },
    });
    const res = await POST(req, mockCtx);
    expect(res.status).toBe(401);
  });

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

  it("returns 400 when content over 200 chars", async () => {
    const req = createRequest("/api/blindbox", {
      method: "POST",
      body: { roomId: "bb-room-1", content: "a".repeat(201) },
    });
    const res = await POST(req, mockCtx);
    expect(res.status).toBe(400);
  });
});

describe("GET /api/blindbox (get pool data)", () => {
  it("returns pool data for valid member", async () => {
    prismaMock.blindBoxIdea.count.mockResolvedValue(5 as never);
    prismaMock.blindBoxIdea.findMany
      .mockResolvedValueOnce([TEST_BLINDBOX_IDEA] as never)
      .mockResolvedValueOnce([] as never);

    const req = createRequest("/api/blindbox?roomId=bb-room-1");
    const res = await GET(req, mockCtx);
    const { status, data } = await parseJsonResponse(res);

    expect(status).toBe(200);
    expect(data.poolCount).toBe(5);
    expect(data.myIdeas).toHaveLength(1);
    expect(data.drawn).toHaveLength(0);
  });

  it("returns 401 when not authenticated", async () => {
    vi.mocked(getAuthUserId).mockRejectedValueOnce(new ApiError("请先登录", 401));
    const req = createRequest("/api/blindbox?roomId=bb-room-1");
    const res = await GET(req, mockCtx);
    expect(res.status).toBe(401);
  });
});

describe("PUT /api/blindbox (edit idea)", () => {
  it("edits an idea successfully", async () => {
    prismaMock.blindBoxIdea.updateMany.mockResolvedValue({ count: 1 } as never);

    const req = createRequest("/api/blindbox", {
      method: "PUT",
      body: { ideaId: "idea-1", content: "去公园散步" },
    });
    const res = await PUT(req, mockCtx);
    const { status, data } = await parseJsonResponse(res);

    expect(status).toBe(200);
    expect(data.content).toBe("去公园散步");
  });

  it("returns 404 when idea not found or already drawn", async () => {
    prismaMock.blindBoxIdea.updateMany.mockResolvedValue({ count: 0 } as never);

    const req = createRequest("/api/blindbox", {
      method: "PUT",
      body: { ideaId: "nonexistent", content: "test" },
    });
    const res = await PUT(req, mockCtx);
    expect(res.status).toBe(404);
  });
});

describe("DELETE /api/blindbox (delete idea)", () => {
  it("deletes an idea successfully", async () => {
    prismaMock.blindBoxIdea.deleteMany.mockResolvedValue({ count: 1 } as never);

    const req = createRequest("/api/blindbox", {
      method: "DELETE",
      body: { ideaId: "idea-1" },
    });
    const res = await DELETE(req, mockCtx);
    const { data } = await parseJsonResponse(res);

    expect(data.deleted).toBe(true);
  });

  it("returns 404 when idea not found or not owned", async () => {
    prismaMock.blindBoxIdea.deleteMany.mockResolvedValue({ count: 0 } as never);

    const req = createRequest("/api/blindbox", {
      method: "DELETE",
      body: { ideaId: "nonexistent" },
    });
    const res = await DELETE(req, mockCtx);
    expect(res.status).toBe(404);
  });
});
