import { describe, it, expect, vi, beforeEach } from "vitest";

const mockGetDb = vi.fn();

vi.mock("../config/database.js", () => ({
  getDb: () => mockGetDb(),
}));

import { KnowledgePointsRepository } from "./knowledge-points.repository.js";

function createMockDb(resolvedValue: unknown): unknown {
  const handler: ProxyHandler<Record<PropertyKey, unknown>> = {
    get: (_target, prop) => {
      if (prop === "then") {
        return (onFulfilled?: (v: unknown) => unknown) =>
          Promise.resolve(
            typeof onFulfilled === "function"
              ? onFulfilled(resolvedValue)
              : resolvedValue,
          );
      }
      return () => new Proxy({}, handler);
    },
  };
  return new Proxy({}, handler);
}

describe("KnowledgePointsRepository", () => {
  let repo: KnowledgePointsRepository;

  beforeEach(() => {
    vi.clearAllMocks();
    repo = new KnowledgePointsRepository();
  });

  it("findById should return first matching knowledge point", async () => {
    const kp = { id: "kp-1", title: "T" };
    mockGetDb.mockReturnValue(createMockDb([kp]));
    const result = await repo.findById("kp-1");
    expect(result).toBe(kp);
  });

  it("findById should return undefined when no match", async () => {
    mockGetDb.mockReturnValue(createMockDb([]));
    const result = await repo.findById("missing");
    expect(result).toBeUndefined();
  });

  it("findByChapterId should return knowledge points array", async () => {
    const kps = [{ id: "kp-1" }];
    mockGetDb.mockReturnValue(createMockDb(kps));
    const result = await repo.findByChapterId("ch-1");
    expect(result).toBe(kps);
  });

  it("create should insert a new knowledge point", async () => {
    mockGetDb.mockReturnValue(createMockDb(undefined));
    await repo.create({
      id: "kp-1",
      chapterId: "ch-1",
      title: "T",
      difficulty: 3,
    });
    expect(mockGetDb).toHaveBeenCalled();
  });

  it("update should update a knowledge point by id", async () => {
    mockGetDb.mockReturnValue(createMockDb(undefined));
    await repo.update("kp-1", { title: "New" });
    expect(mockGetDb).toHaveBeenCalled();
  });

  it("delete should delete a knowledge point by id", async () => {
    mockGetDb.mockReturnValue(createMockDb(undefined));
    await repo.delete("kp-1");
    expect(mockGetDb).toHaveBeenCalled();
  });
});
