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

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

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

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

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

describe("GET /api/user/history", () => {
  it("returns empty array when no history", async () => {
    prismaMock.decision.findMany.mockResolvedValue([] as never);
    const req = createRequest("/api/user/history");
    const res = await GET(req, mockCtx);
    const { data } = await parseJsonResponse(res);
    expect(data).toEqual([]);
  });

  it("returns decision history", async () => {
    prismaMock.decision.findMany.mockResolvedValue([
      {
        id: "dec-1",
        userId: "user-1",
        roomId: "room-1",
        restaurantName: "测试餐厅",
        restaurantData: JSON.stringify(TEST_RESTAURANT),
        matchType: "unanimous",
        participants: 2,
        createdAt: new Date("2025-01-01"),
      },
    ] as never);

    const req = createRequest("/api/user/history");
    const res = await GET(req, mockCtx);
    const { status, data } = await parseJsonResponse(res);

    expect(status).toBe(200);
    expect(data).toHaveLength(1);
    expect(data[0].restaurantName).toBe("测试餐厅");
  });
});

describe("POST /api/user/history", () => {
  it("saves a decision", async () => {
    prismaMock.user.findUnique.mockResolvedValue(TEST_USER as never);
    prismaMock.decision.findFirst.mockResolvedValue(null as never);
    prismaMock.decision.create.mockResolvedValue({ id: "dec-new" } as never);
    prismaMock.decision.count.mockResolvedValue(1 as never);

    const req = createRequest("/api/user/history", {
      method: "POST",
      body: {
        roomId: "room-1",
        restaurant: TEST_RESTAURANT,
        matchType: "unanimous",
        participants: 2,
      },
    });
    const res = await POST(req, mockCtx);
    const { status, data } = await parseJsonResponse(res);

    expect(status).toBe(200);
    expect(data.id).toBe("dec-new");
  });

  it("returns alreadyExists for duplicate room", async () => {
    prismaMock.user.findUnique.mockResolvedValue(TEST_USER as never);
    prismaMock.decision.findFirst.mockResolvedValue({ id: "existing" } as never);

    const req = createRequest("/api/user/history", {
      method: "POST",
      body: {
        roomId: "room-1",
        restaurant: TEST_RESTAURANT,
        matchType: "unanimous",
      },
    });
    const res = await POST(req, mockCtx);
    const { data } = await parseJsonResponse(res);

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

  it("trims history to 50 records", async () => {
    prismaMock.user.findUnique.mockResolvedValue(TEST_USER as never);
    prismaMock.decision.findFirst.mockResolvedValue(null as never);
    prismaMock.decision.create.mockResolvedValue({ id: "dec-new" } as never);
    prismaMock.decision.count.mockResolvedValue(51 as never);
    prismaMock.decision.findMany.mockResolvedValue([{ id: "old-1" }] as never);
    prismaMock.decision.deleteMany.mockResolvedValue({ count: 1 } as never);

    const req = createRequest("/api/user/history", {
      method: "POST",
      body: {
        roomId: "room-1",
        restaurant: TEST_RESTAURANT,
        matchType: "best",
      },
    });
    const res = await POST(req, mockCtx);
    expect(res.status).toBe(200);
    expect(prismaMock.decision.deleteMany).toHaveBeenCalled();
  });

  it("returns 400 when missing required fields", async () => {
    const req = createRequest("/api/user/history", {
      method: "POST",
      body: {},
    });
    const res = await POST(req, mockCtx);
    expect(res.status).toBe(400);
  });

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