/**
 * Tests for Review Questions Service (Convex-backed)
 */

// Mock dependencies before imports
jest.mock("@/lib/convex-client", () => ({
  __esModule: true,
  convexQuery: jest.fn().mockResolvedValue(null),
  convexMutation: jest.fn().mockResolvedValue(null),
  convexAction: jest.fn().mockResolvedValue(null),
}));

jest.mock("@/lib/services/openrouter.service", () => ({
  openRouterService: {
    isConfigured: jest.fn(),
    chatCompletion: jest.fn(),
  },
}));

jest.mock("@/lib/logger", () => ({
  logger: {
    scope: jest.fn().mockReturnValue({
      info: jest.fn(),
      warn: jest.fn(),
      error: jest.fn(),
      debug: jest.fn(),
    }),
  },
}));

import { convexQuery, convexMutation } from "@/lib/convex-client";
import {
  generateReviewQuestions,
  getOrCreateQuestionTemplate,
  updateQuestionTemplate,
  listQuestionTemplates,
  deleteQuestionTemplate,
} from "@/lib/services/review-questions.service";
import { openRouterService } from "@/lib/services/openrouter.service";

const mockConvexQuery = convexQuery as jest.Mock;
const mockConvexMutation = convexMutation as jest.Mock;
const mockOpenRouter = openRouterService as jest.Mocked<
  typeof openRouterService
>;

describe("generateReviewQuestions", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it("returns AI-generated bilingual questions when OpenRouter is configured", async () => {
    mockOpenRouter.isConfigured.mockReturnValue(true);
    const mockQuestions = [
      { questionEn: "How was the service?", questionAr: "كيف كانت الخدمة؟" },
      { questionEn: "Would you recommend?", questionAr: "هل تنصح؟" },
    ];
    mockOpenRouter.chatCompletion.mockResolvedValueOnce({
      success: true,
      content: JSON.stringify(mockQuestions),
      model: "qwen/qwen3-30b-a3b",
    });

    const result = await generateReviewQuestions("healthcare", "en", 2);
    expect(result).toHaveLength(2);
    expect(result[0]).toHaveProperty("questionEn");
    expect(result[0]).toHaveProperty("questionAr");
  });

  it("falls back to defaults when OpenRouter is not configured", async () => {
    mockOpenRouter.isConfigured.mockReturnValue(false);

    const result = await generateReviewQuestions("healthcare", "en", 3);
    expect(result).toHaveLength(3);
    expect(result[0].questionEn).toContain("quality of care");
    expect(mockOpenRouter.chatCompletion).not.toHaveBeenCalled();
  });

  it("falls back to defaults on AI error", async () => {
    mockOpenRouter.isConfigured.mockReturnValue(true);
    mockOpenRouter.chatCompletion.mockResolvedValueOnce({
      success: false,
      error: "API error",
      content: "",
      model: "",
    });

    const result = await generateReviewQuestions("healthcare", "en", 5);
    expect(result).toHaveLength(5);
    expect(result[0]).toHaveProperty("questionEn");
  });

  it("falls back to general defaults for unknown industry", async () => {
    mockOpenRouter.isConfigured.mockReturnValue(false);

    const result = await generateReviewQuestions("unknown-industry", "en", 3);
    expect(result).toHaveLength(3);
    expect(result[0].questionEn).toContain("overall experience");
  });

  it("falls back to defaults when AI returns invalid JSON", async () => {
    mockOpenRouter.isConfigured.mockReturnValue(true);
    mockOpenRouter.chatCompletion.mockResolvedValueOnce({
      success: true,
      content: "not valid json",
      model: "qwen/qwen3-30b-a3b",
    });

    const result = await generateReviewQuestions("beauty", "en", 3);
    expect(result).toHaveLength(3);
    expect(result[0].questionEn).toContain("satisfied");
  });
});

describe("getOrCreateQuestionTemplate", () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockOpenRouter.isConfigured.mockReturnValue(false); // force defaults
  });

  it("returns existing template when found", async () => {
    const mockTemplate = {
      _id: "convex-tmpl-1",
      prismaId: "tmpl-1",
      userId: "user-1",
      industry: "healthcare",
      questions: [{ questionEn: "Q?", questionAr: "س؟" }],
      isDefault: true,
      createdAt: Date.now(),
      updatedAt: Date.now(),
    };
    mockConvexQuery.mockResolvedValueOnce(mockTemplate);

    const result = await getOrCreateQuestionTemplate("user-1", "healthcare");
    expect(result.id).toBe("tmpl-1"); // uses prismaId
    expect(result.questions).toHaveLength(1);
    expect(mockConvexMutation).not.toHaveBeenCalled();
  });

  it("creates new template when none exists", async () => {
    mockConvexQuery.mockResolvedValueOnce(null); // no existing template

    const mockCreated = {
      _id: "convex-new-id",
      userId: "user-1",
      industry: "healthcare",
      questions: [
        {
          questionEn: "How would you rate the quality of care you received?",
          questionAr: "كيف تقيّم جودة الرعاية التي حصلت عليها؟",
        },
      ],
      isDefault: true,
      createdAt: Date.now(),
      updatedAt: Date.now(),
    };
    mockConvexMutation.mockResolvedValueOnce(mockCreated);

    const result = await getOrCreateQuestionTemplate("user-1", "healthcare");
    expect(mockConvexMutation).toHaveBeenCalledWith(
      "reviews/mutations:createQuestionTemplate",
      expect.objectContaining({
        userId: "user-1",
        industry: "healthcare",
        isDefault: true,
      }),
    );
    expect(result.id).toBe("convex-new-id");
  });

  it("uses correct industry defaults for known industry", async () => {
    mockConvexQuery.mockResolvedValueOnce(null);
    mockConvexMutation.mockImplementation(
      (_path: string, args: Record<string, unknown>) => ({
        _id: "convex-new-id",
        ...args,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      }),
    );

    const result = await getOrCreateQuestionTemplate("user-1", "beauty");
    expect(result.questions[0].questionEn).toContain("satisfied");
  });
});

describe("updateQuestionTemplate", () => {
  beforeEach(() => jest.clearAllMocks());

  it("updates questions in template", async () => {
    const templates = [
      {
        _id: "convex-tmpl-1",
        prismaId: "tmpl-1",
        userId: "user-1",
        industry: "healthcare",
        questions: [{ questionEn: "Old Q?", questionAr: "سؤال قديم؟" }],
        isDefault: true,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      },
    ];
    mockConvexQuery.mockResolvedValueOnce(templates);
    mockConvexMutation.mockResolvedValueOnce("convex-tmpl-1");

    const newQuestions = [{ questionEn: "New Q?", questionAr: "سؤال جديد؟" }];
    const result = await updateQuestionTemplate(
      "user-1",
      "tmpl-1",
      newQuestions,
    );
    expect(result.isDefault).toBe(false);
    expect(result.questions).toEqual(newQuestions);
  });

  it("throws TEMPLATE_NOT_FOUND for missing template", async () => {
    mockConvexQuery.mockResolvedValueOnce([]);

    await expect(
      updateQuestionTemplate("user-1", "nonexistent", []),
    ).rejects.toThrow("TEMPLATE_NOT_FOUND");
  });

  it("throws TEMPLATE_ACCESS_DENIED for non-owner", async () => {
    mockConvexQuery.mockResolvedValueOnce([
      {
        _id: "convex-tmpl-1",
        prismaId: "tmpl-1",
        userId: "other-user",
        industry: "healthcare",
        questions: [],
        isDefault: true,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      },
    ]);

    await expect(
      updateQuestionTemplate("user-1", "tmpl-1", []),
    ).rejects.toThrow("TEMPLATE_ACCESS_DENIED");
  });
});

describe("listQuestionTemplates", () => {
  beforeEach(() => jest.clearAllMocks());

  it("returns user templates mapped from Convex docs", async () => {
    const mockTemplates = [
      {
        _id: "convex-tmpl-2",
        userId: "user-1",
        industry: "beauty",
        questions: [],
        isDefault: true,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      },
      {
        _id: "convex-tmpl-1",
        userId: "user-1",
        industry: "healthcare",
        questions: [],
        isDefault: true,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      },
    ];
    mockConvexQuery.mockResolvedValueOnce(mockTemplates);

    const result = await listQuestionTemplates("user-1");
    expect(result).toHaveLength(2);
    expect(mockConvexQuery).toHaveBeenCalledWith(
      "reviews/queries:getQuestionTemplates",
      { userId: "user-1" },
    );
  });
});

describe("deleteQuestionTemplate", () => {
  beforeEach(() => jest.clearAllMocks());

  it("deletes owned template", async () => {
    mockConvexQuery.mockResolvedValueOnce([
      {
        _id: "convex-tmpl-1",
        prismaId: "tmpl-1",
        userId: "user-1",
        industry: "healthcare",
        questions: [],
        isDefault: true,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      },
    ]);
    mockConvexMutation.mockResolvedValueOnce(null);

    await deleteQuestionTemplate("user-1", "tmpl-1");
    expect(mockConvexMutation).toHaveBeenCalledWith(
      "reviews/mutations:deleteQuestionTemplate",
      { templateId: "convex-tmpl-1" },
    );
  });

  it("throws TEMPLATE_NOT_FOUND for missing template", async () => {
    mockConvexQuery.mockResolvedValueOnce([]);

    await expect(
      deleteQuestionTemplate("user-1", "nonexistent"),
    ).rejects.toThrow("TEMPLATE_NOT_FOUND");
  });

  it("throws TEMPLATE_ACCESS_DENIED for non-owner", async () => {
    mockConvexQuery.mockResolvedValueOnce([
      {
        _id: "convex-tmpl-1",
        prismaId: "tmpl-1",
        userId: "other-user",
        industry: "healthcare",
        questions: [],
        isDefault: true,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      },
    ]);

    await expect(deleteQuestionTemplate("user-1", "tmpl-1")).rejects.toThrow(
      "TEMPLATE_ACCESS_DENIED",
    );
  });
});
