import { describe, test, expect, beforeAll, afterAll, mock } from "bun:test";
import { db } from "@/db";
import { annotators } from "@/db/schema";
import { eq } from "drizzle-orm";

// Mock cookie store that captures set/delete calls
const cookieJar = new Map<string, string>();
const mockCookieStore = {
  get(name: string) {
    const value = cookieJar.get(name);
    return value ? { value } : undefined;
  },
  set(name: string, value: string, _opts?: unknown) {
    cookieJar.set(name, value);
  },
  delete(name: string) {
    cookieJar.delete(name);
  },
};

// Mock next/headers before importing route handlers
mock.module("next/headers", () => ({
  cookies: async () => mockCookieStore,
}));

// Import route handlers after mock is set up
const { GET, POST, DELETE: DELETE_HANDLER } = await import("../route");

const TEST_ANNOTATOR = {
  id: "test-auth-user",
  displayName: "Test Auth User",
  password: "testpass",
};

beforeAll(async () => {
  await db.delete(annotators).where(eq(annotators.id, TEST_ANNOTATOR.id));
  await db.insert(annotators).values(TEST_ANNOTATOR);
});

afterAll(async () => {
  await db.delete(annotators).where(eq(annotators.id, TEST_ANNOTATOR.id));
});

describe("GET /api/auth", () => {
  test("returns annotator list without passwords", async () => {
    const res = await GET();
    const data = await res.json();

    expect(Array.isArray(data)).toBe(true);

    const testAnnotator = data.find(
      (a: { id: string }) => a.id === TEST_ANNOTATOR.id,
    );
    expect(testAnnotator).toBeDefined();
    expect(testAnnotator.id).toBe(TEST_ANNOTATOR.id);
    expect(testAnnotator.displayName).toBe(TEST_ANNOTATOR.displayName);
    expect(testAnnotator.password).toBeUndefined();
  });
});

describe("POST /api/auth", () => {
  test("returns 200 and sets session cookie with correct credentials", async () => {
    cookieJar.clear();

    const req = new Request("http://localhost:3000/api/auth", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        annotatorId: TEST_ANNOTATOR.id,
        password: TEST_ANNOTATOR.password,
      }),
    });

    const res = await POST(req);
    const data = await res.json();

    expect(res.status).toBe(200);
    expect(data.ok).toBe(true);
    expect(data.annotator.id).toBe(TEST_ANNOTATOR.id);
    expect(data.annotator.displayName).toBe(TEST_ANNOTATOR.displayName);

    // Verify session cookie was set in the mock store
    expect(cookieJar.has("session")).toBe(true);
    const sessionValue = cookieJar.get("session")!;
    expect(sessionValue).toContain(".");
  });

  test("returns 401 with wrong password", async () => {
    const req = new Request("http://localhost:3000/api/auth", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        annotatorId: TEST_ANNOTATOR.id,
        password: "wrongpassword",
      }),
    });

    const res = await POST(req);
    const data = await res.json();

    expect(res.status).toBe(401);
    expect(data.error).toBe("Invalid credentials");
  });

  test("returns 401 with nonexistent annotator", async () => {
    const req = new Request("http://localhost:3000/api/auth", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        annotatorId: "nonexistent-user",
        password: "anything",
      }),
    });

    const res = await POST(req);
    expect(res.status).toBe(401);
  });

  test("returns 401 with missing fields", async () => {
    const req = new Request("http://localhost:3000/api/auth", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({}),
    });

    const res = await POST(req);
    expect(res.status).toBe(401);
  });
});

describe("DELETE /api/auth", () => {
  test("clears session cookie", async () => {
    // Pre-populate a session cookie
    cookieJar.set("session", "fake-session-value");

    const res = await DELETE_HANDLER();
    const data = await res.json();

    expect(res.status).toBe(200);
    expect(data.ok).toBe(true);
    expect(cookieJar.has("session")).toBe(false);
  });
});
