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

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.module("next/headers", () => ({
  cookies: async () => mockCookieStore,
}));

const { createSession } = await import("@/lib/auth");
const { GET, POST } = await import("../route");

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

const QUIZ_SESSION_ID = "test-warmup-quiz-session";

beforeAll(async () => {
  // Clean up any leftover data
  await db
    .delete(quizSessions)
    .where(eq(quizSessions.annotatorId, TEST_ANNOTATOR.id));
  await db.delete(annotators).where(eq(annotators.id, TEST_ANNOTATOR.id));

  // Create test annotator
  await db.insert(annotators).values(TEST_ANNOTATOR);

  // Create a passed quiz session
  await db.insert(quizSessions).values({
    id: QUIZ_SESSION_ID,
    annotatorId: TEST_ANNOTATOR.id,
    totalQuestions: 8,
    score: 8,
    passed: true,
    completedAt: new Date(),
    answers: "[]",
  });

  // Set up session cookie
  cookieJar.clear();
  await createSession(TEST_ANNOTATOR.id);
});

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

describe("GET /api/warmup", () => {
  test("returns first warmup paragraph", async () => {
    const res = await GET();
    const data = await res.json();

    expect(res.status).toBe(200);
    expect(data.done).toBe(false);
    expect(data.warmupCompleted).toBe(0);
    expect(data.paragraph).toBeDefined();
    expect(data.paragraph.id).toBe("warmup-1");
    expect(data.paragraph.text).toBeTruthy();
    expect(data.paragraph.index).toBe(0);
    expect(data.paragraph.total).toBe(5);
  });
});

describe("POST /api/warmup", () => {
  test("returns gold answer and explanation for correct answer", async () => {
    const req = new Request("http://localhost:3000/api/warmup", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        category: "Board Governance",
        specificity: 3,
        warmupIndex: 0,
      }),
    });

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

    expect(res.status).toBe(200);
    expect(data.categoryCorrect).toBe(true);
    expect(data.specificityCorrect).toBe(true);
    expect(data.goldCategory).toBe("Board Governance");
    expect(data.goldSpecificity).toBe(3);
    expect(data.explanation).toBeTruthy();
    expect(data.warmupCompleted).toBe(1);
    expect(data.done).toBe(false);
  });

  test("returns feedback for incorrect answer", async () => {
    const req = new Request("http://localhost:3000/api/warmup", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        category: "Management Role",
        specificity: 1,
        warmupIndex: 1,
      }),
    });

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

    expect(res.status).toBe(200);
    expect(data.categoryCorrect).toBe(false);
    expect(data.specificityCorrect).toBe(false);
    expect(data.goldCategory).toBe("Incident Disclosure");
    expect(data.goldSpecificity).toBe(4);
    expect(data.warmupCompleted).toBe(2);
  });

  test("rejects mismatched warmup index", async () => {
    const req = new Request("http://localhost:3000/api/warmup", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        category: "Risk Management Process",
        specificity: 1,
        warmupIndex: 0, // should be 2 at this point
      }),
    });

    const res = await POST(req);
    expect(res.status).toBe(400);
    const data = await res.json();
    expect(data.error).toBe("Warmup index mismatch");
  });

  test("completes remaining warmups and returns done", async () => {
    // Complete warmups 2, 3, 4
    for (let i = 2; i < 5; i++) {
      const req = new Request("http://localhost:3000/api/warmup", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          category: "None/Other",
          specificity: 1,
          warmupIndex: i,
        }),
      });
      const res = await POST(req);
      expect(res.status).toBe(200);
    }

    // GET should now return done
    const res = await GET();
    const data = await res.json();
    expect(data.done).toBe(true);
    expect(data.warmupCompleted).toBe(5);
  });
});

describe("GET /api/warmup - unauthorized", () => {
  test("returns 401 without session", async () => {
    cookieJar.clear();
    const res = await GET();
    expect(res.status).toBe(401);
  });
});
