import { describe, it, expect, vi, beforeEach } from "vitest";
import { createRequest, createRouteContext, parseJsonResponse } from "@/__tests__/helpers/api-test-utils";
import { TEST_ROOM_DATA, TEST_RESTAURANT } from "@/__tests__/helpers/fixtures";

vi.mock("@/lib/prisma", () => ({ prisma: {} }));

vi.mock("@/lib/roomRepository", () => ({
  atomicUpdateRoom: vi.fn(),
}));

vi.mock("@/lib/roomEvents", () => ({
  notify: vi.fn(),
}));

import { POST } from "./route";
import { atomicUpdateRoom } from "@/lib/roomRepository";

const mockAtomicUpdate = vi.mocked(atomicUpdateRoom);

beforeEach(() => {
  vi.clearAllMocks();
});

describe("POST /api/room/[id]/swipe", () => {
  it("records a like action", async () => {
    mockAtomicUpdate.mockImplementation(async (_id, updater) => {
      const data = structuredClone(TEST_ROOM_DATA);
      return updater(data);
    });

    const req = createRequest("/api/room/ROOM01/swipe", {
      method: "POST",
      body: { userId: "user-1", restaurantId: TEST_RESTAURANT.id, action: "like" },
    });
    const ctx = createRouteContext({ id: "ROOM01" });
    const res = await POST(req, ctx);
    const { status, data } = await parseJsonResponse(res);

    expect(status).toBe(200);
    expect(data.likeCount).toBe(1);
  });

  it("records a pass action", async () => {
    mockAtomicUpdate.mockImplementation(async (_id, updater) => {
      const data = structuredClone(TEST_ROOM_DATA);
      return updater(data);
    });

    const req = createRequest("/api/room/ROOM01/swipe", {
      method: "POST",
      body: { userId: "user-1", restaurantId: TEST_RESTAURANT.id, action: "pass" },
    });
    const ctx = createRouteContext({ id: "ROOM01" });
    const res = await POST(req, ctx);
    const { status, data } = await parseJsonResponse(res);

    expect(status).toBe(200);
    expect(data.match).toBeNull();
  });

  it("sets match when all users like same restaurant", async () => {
    mockAtomicUpdate.mockImplementation(async (_id, updater) => {
      const data = structuredClone(TEST_ROOM_DATA);
      data.likes[TEST_RESTAURANT.id] = ["user-2"];
      return updater(data);
    });

    const req = createRequest("/api/room/ROOM01/swipe", {
      method: "POST",
      body: { userId: "user-1", restaurantId: TEST_RESTAURANT.id, action: "like" },
    });
    const ctx = createRouteContext({ id: "ROOM01" });
    const res = await POST(req, ctx);
    const { data } = await parseJsonResponse(res);

    expect(data.match).toBe(TEST_RESTAURANT.id);
    expect(data.likeCount).toBe(2);
  });

  it("returns 403 when user is not a member", async () => {
    mockAtomicUpdate.mockImplementation(async (_id, updater) => {
      const data = structuredClone(TEST_ROOM_DATA);
      data.users = ["other-user"];
      return updater(data);
    });

    const req = createRequest("/api/room/ROOM01/swipe", {
      method: "POST",
      body: { userId: "user-1", restaurantId: TEST_RESTAURANT.id, action: "like" },
    });
    const ctx = createRouteContext({ id: "ROOM01" });
    const res = await POST(req, ctx);
    expect(res.status).toBe(403);
  });

  it("returns 400 for invalid action", async () => {
    const req = createRequest("/api/room/ROOM01/swipe", {
      method: "POST",
      body: { userId: "user-1", restaurantId: TEST_RESTAURANT.id, action: "invalid" },
    });
    const ctx = createRouteContext({ id: "ROOM01" });
    const res = await POST(req, ctx);
    expect(res.status).toBe(400);
  });

  it("returns 400 when missing restaurantId", async () => {
    const req = createRequest("/api/room/ROOM01/swipe", {
      method: "POST",
      body: { userId: "user-1", action: "like" },
    });
    const ctx = createRouteContext({ id: "ROOM01" });
    const res = await POST(req, ctx);
    expect(res.status).toBe(400);
  });

  it("returns 400 when restaurantId is not in room candidates", async () => {
    mockAtomicUpdate.mockImplementation(async (_id, updater) => {
      const data = structuredClone(TEST_ROOM_DATA);
      return updater(data);
    });

    const req = createRequest("/api/room/ROOM01/swipe", {
      method: "POST",
      body: { userId: "user-1", restaurantId: "unknown-id", action: "like" },
    });
    const ctx = createRouteContext({ id: "ROOM01" });
    const res = await POST(req, ctx);
    expect(res.status).toBe(400);
  });

  it("returns 404 when room not found", async () => {
    mockAtomicUpdate.mockResolvedValue(null);

    const req = createRequest("/api/room/ROOM01/swipe", {
      method: "POST",
      body: { userId: "user-1", restaurantId: TEST_RESTAURANT.id, action: "like" },
    });
    const ctx = createRouteContext({ id: "ROOM01" });
    const res = await POST(req, ctx);
    expect(res.status).toBe(404);
  });
});
