import { describe, it, expect, vi, beforeEach } from "vitest";
import { QuestionsController } from "./questions.controller.js";

vi.mock("./questions.service.js", () => ({
  QuestionsService: vi.fn(),
}));

const mockService = {
  createQuestion: vi.fn(),
  list: vi.fn(),
  listByKnowledgePoint: vi.fn(),
  getQuestion: vi.fn(),
  updateQuestion: vi.fn(),
  deleteQuestion: vi.fn(),
};

describe("QuestionsController", () => {
  let controller: QuestionsController;

  beforeEach(() => {
    vi.clearAllMocks();
    controller = new QuestionsController(mockService as never);
  });

  describe("create", () => {
    it("should parse input and call service.createQuestion", async () => {
      mockService.createQuestion.mockResolvedValue({ id: "q-1" });
      const result = await controller.create({
        knowledgePointId: "kp-1",
        type: "single_choice",
        content: "What is 2+2?",
        answer: "4",
        createdBy: "user-1",
      });
      expect(mockService.createQuestion).toHaveBeenCalledWith(
        expect.objectContaining({
          knowledgePointId: "kp-1",
          type: "single_choice",
          answer: "4",
        }),
      );
      expect(result).toEqual({ success: true, data: { id: "q-1" } });
    });

    it("should throw on invalid body", async () => {
      await expect(
        controller.create({ knowledgePointId: "kp-1", type: "invalid" }),
      ).rejects.toThrow();
    });
  });

  describe("list", () => {
    it("should parse query and call service.list", async () => {
      const data = [{ id: "q-1" }];
      mockService.list.mockResolvedValue(data);
      const result = await controller.list({ page: "1", pageSize: "20" });
      expect(mockService.list).toHaveBeenCalledWith(
        expect.objectContaining({ page: 1, pageSize: 20 }),
      );
      expect(result).toEqual({ success: true, data });
    });
  });

  describe("listByKnowledgePoint", () => {
    it("should call service.listByKnowledgePoint", async () => {
      const data = [{ id: "q-1" }];
      mockService.listByKnowledgePoint.mockResolvedValue(data);
      const result = await controller.listByKnowledgePoint("kp-1");
      expect(mockService.listByKnowledgePoint).toHaveBeenCalledWith("kp-1");
      expect(result).toEqual({ success: true, data });
    });
  });

  describe("getById", () => {
    it("should call service.getQuestion", async () => {
      const data = { id: "q-1", content: "Q" };
      mockService.getQuestion.mockResolvedValue(data);
      const result = await controller.getById("q-1");
      expect(mockService.getQuestion).toHaveBeenCalledWith("q-1");
      expect(result).toEqual({ success: true, data });
    });
  });

  describe("update", () => {
    it("should parse input and call service.updateQuestion", async () => {
      const result = await controller.update("q-1", { content: "New content" });
      expect(mockService.updateQuestion).toHaveBeenCalledWith("q-1", {
        content: "New content",
      });
      expect(result).toEqual({ success: true, data: { success: true } });
    });

    it("should throw on invalid status", async () => {
      await expect(
        controller.update("q-1", { status: "invalid" }),
      ).rejects.toThrow();
    });
  });

  describe("remove", () => {
    it("should call service.deleteQuestion", async () => {
      const result = await controller.remove("q-1");
      expect(mockService.deleteQuestion).toHaveBeenCalledWith("q-1");
      expect(result).toEqual({ success: true, data: { success: true } });
    });
  });
});
