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

const mockGetDb = vi.fn();

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

import { ChaptersRepository } from "./chapters.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("ChaptersRepository", () => {
  let repo: ChaptersRepository;

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

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

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

  it("findByTextbookId should return chapters array", async () => {
    const chapters = [{ id: "ch-1" }, { id: "ch-2" }];
    mockGetDb.mockReturnValue(createMockDb(chapters));
    const result = await repo.findByTextbookId("tb-1");
    expect(result).toBe(chapters);
  });

  it("create should insert a new chapter", async () => {
    mockGetDb.mockReturnValue(createMockDb(undefined));
    await repo.create({
      id: "ch-1",
      textbookId: "tb-1",
      title: "T",
      order: 0,
      status: "draft",
    });
    expect(mockGetDb).toHaveBeenCalled();
  });

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

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