/**
 * Tests for review questions API routes (flat questions model)
 * GET/POST  /api/dashboard/reviews/questions
 * PUT/DELETE /api/dashboard/reviews/questions/[questionId]
 * POST /api/dashboard/reviews/questions/generate
 */

jest.mock("@/lib/auth", () => ({ auth: jest.fn() }));
jest.mock("@/lib/utils/auth-helpers.util", () => ({
  getAuthenticatedUser: jest.fn(),
}));
jest.mock("@/lib/utils/organization-data", () => ({
  getEffectiveOwnerId: jest.fn((id: string) => id),
}));
jest.mock("@paralleldrive/cuid2", () => ({ createId: () => "test-cuid" }));
jest.mock("@/lib/db");
jest.mock("@/lib/services/review-questions.service", () => ({
  listQuestionTemplates: jest.fn(),
  getOrCreateQuestionTemplate: jest.fn(),
  updateQuestionTemplate: jest.fn(),
  deleteQuestionTemplate: jest.fn(),
  generateReviewQuestions: jest.fn(),
}));
jest.mock("@/lib/logger", () => ({
  logger: {
    scope: () => ({
      info: jest.fn(),
      error: jest.fn(),
      warn: jest.fn(),
      debug: jest.fn(),
    }),
  },
}));
jest.mock("@/lib/data-source", () => ({
  getDataSource: jest.fn(() => "prisma"),
}));

import { NextRequest } from "next/server";
import { getAuthenticatedUser } from "@/lib/utils/auth-helpers.util";
import { prisma } from "@/lib/db";
import * as questionsService from "@/lib/services/review-questions.service";

const mockUser = { userId: "user-1", email: "test@test.com" };
const mockDb = prisma as jest.Mocked<typeof prisma>;

const EXISTING_TEMPLATE = {
  id: "tmpl-1",
  userId: "user-1",
  industry: "general",
  isDefault: true,
  questions: [
    {
      id: "q1",
      questionEn: "How was your experience?",
      questionAr: "كيف كانت تجربتك؟",
      type: "rating",
      sortOrder: 0,
    },
    {
      id: "q2",
      questionEn: "Would you recommend us?",
      questionAr: "هل تنصح بنا؟",
      type: "yesno",
      sortOrder: 1,
    },
  ],
  createdAt: new Date(),
  updatedAt: new Date(),
};

function makeReq(url: string, method = "GET", body?: object) {
  const opts: RequestInit = { method };
  if (body) {
    opts.body = JSON.stringify(body);
    opts.headers = { "Content-Type": "application/json" };
  }
  return new NextRequest(`http://localhost:9000${url}`, opts);
}

// ─── GET /api/dashboard/reviews/questions ───────────────────────────────────

describe("GET /api/dashboard/reviews/questions", () => {
  let mod: typeof import("@/app/api/dashboard/reviews/questions/route");
  beforeAll(async () => {
    mod = await import("@/app/api/dashboard/reviews/questions/route");
  });
  beforeEach(() => jest.clearAllMocks());

  it("returns 401 when unauthenticated", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(null);
    const res = await mod.GET(makeReq("/api/dashboard/reviews/questions"));
    expect(res.status).toBe(401);
    const json = await res.json();
    expect(json.success).toBe(false);
  });

  it("returns flat questions list from existing template", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(EXISTING_TEMPLATE);

    const res = await mod.GET(makeReq("/api/dashboard/reviews/questions"));
    expect(res.status).toBe(200);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(json.questions).toHaveLength(2);
    expect(json.questions[0]).toMatchObject({ id: "q1", type: "rating" });
    expect(json.questions[1]).toMatchObject({ id: "q2", type: "yesno" });
  });

  it("creates default template and returns questions for new user", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(null);
    (mockDb.review_question_templates.create as jest.Mock).mockResolvedValue({
      ...EXISTING_TEMPLATE,
      id: "tmpl-new",
      questions: [
        {
          id: "test-cuid",
          questionEn: "How would you rate your overall experience?",
          questionAr: "كيف تقيّم تجربتك بشكل عام؟",
          type: "rating",
          sortOrder: 0,
        },
      ],
    });

    const res = await mod.GET(makeReq("/api/dashboard/reviews/questions"));
    expect(res.status).toBe(200);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(Array.isArray(json.questions)).toBe(true);
    expect(mockDb.review_question_templates.create).toHaveBeenCalled();
  });

  it("returns 500 on db error", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockRejectedValue(new Error("DB error"));

    const res = await mod.GET(makeReq("/api/dashboard/reviews/questions"));
    expect(res.status).toBe(500);
  });
});

// ─── POST /api/dashboard/reviews/questions ──────────────────────────────────

describe("POST /api/dashboard/reviews/questions", () => {
  let mod: typeof import("@/app/api/dashboard/reviews/questions/route");
  beforeAll(async () => {
    mod = await import("@/app/api/dashboard/reviews/questions/route");
  });
  beforeEach(() => jest.clearAllMocks());

  it("returns 401 when unauthenticated", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(null);
    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions", "POST", { questionEn: "Q?" }),
    );
    expect(res.status).toBe(401);
  });

  it("adds a new question to the template", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(EXISTING_TEMPLATE);
    (mockDb.review_question_templates.update as jest.Mock).mockResolvedValue(
      EXISTING_TEMPLATE,
    );

    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions", "POST", {
        questionEn: "Any other comments?",
        questionAr: "أي تعليقات أخرى؟",
        type: "text",
      }),
    );
    expect(res.status).toBe(201);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(json.question).toMatchObject({
      questionEn: "Any other comments?",
      type: "text",
    });
    expect(mockDb.review_question_templates.update).toHaveBeenCalled();
  });

  it("adds a yesno type question", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(EXISTING_TEMPLATE);
    (mockDb.review_question_templates.update as jest.Mock).mockResolvedValue(
      EXISTING_TEMPLATE,
    );

    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions", "POST", {
        questionEn: "Would you return?",
        questionAr: "هل ستعود؟",
        type: "yesno",
      }),
    );
    expect(res.status).toBe(201);
    const json = await res.json();
    expect(json.question.type).toBe("yesno");
  });

  it("returns 400 for empty questionEn", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions", "POST", { questionEn: "" }),
    );
    expect(res.status).toBe(400);
  });

  it("returns 400 for invalid type", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions", "POST", {
        questionEn: "Q?",
        type: "checkbox",
      }),
    );
    expect(res.status).toBe(400);
  });
});

// ─── PUT /api/dashboard/reviews/questions/[questionId] ──────────────────────

describe("PUT /api/dashboard/reviews/questions/[questionId]", () => {
  let mod: typeof import("@/app/api/dashboard/reviews/questions/[templateId]/route");
  beforeAll(async () => {
    mod =
      await import("@/app/api/dashboard/reviews/questions/[templateId]/route");
  });
  beforeEach(() => jest.clearAllMocks());

  const makeParams = (templateId: string) => Promise.resolve({ templateId });

  it("returns 401 when unauthenticated", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(null);
    const res = await mod.PUT(
      makeReq("/api/dashboard/reviews/questions/q1", "PUT", {
        questionEn: "Updated?",
        questionAr: "محدّث؟",
        type: "rating",
      }),
      { params: makeParams("q1") },
    );
    expect(res.status).toBe(401);
  });

  it("updates a question by ID", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(EXISTING_TEMPLATE);
    (mockDb.review_question_templates.update as jest.Mock).mockResolvedValue(
      EXISTING_TEMPLATE,
    );

    const res = await mod.PUT(
      makeReq("/api/dashboard/reviews/questions/q1", "PUT", {
        questionEn: "Updated question?",
        questionAr: "سؤال محدّث؟",
        type: "rating",
      }),
      { params: makeParams("q1") },
    );
    expect(res.status).toBe(200);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(mockDb.review_question_templates.update).toHaveBeenCalled();
  });

  it("updates question type to yesno", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(EXISTING_TEMPLATE);
    (mockDb.review_question_templates.update as jest.Mock).mockResolvedValue(
      EXISTING_TEMPLATE,
    );

    const res = await mod.PUT(
      makeReq("/api/dashboard/reviews/questions/q1", "PUT", {
        questionEn: "Recommend?",
        questionAr: "تنصح؟",
        type: "yesno",
      }),
      { params: makeParams("q1") },
    );
    expect(res.status).toBe(200);
  });

  it("returns 404 when question template not found", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(null);

    const res = await mod.PUT(
      makeReq("/api/dashboard/reviews/questions/q-none", "PUT", {
        questionEn: "Q?",
        questionAr: "س؟",
        type: "text",
      }),
      { params: makeParams("q-none") },
    );
    expect(res.status).toBe(404);
  });

  it("returns 404 when question ID not found in template", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(EXISTING_TEMPLATE);

    const res = await mod.PUT(
      makeReq("/api/dashboard/reviews/questions/q-nonexistent", "PUT", {
        questionEn: "Q?",
        questionAr: "س؟",
        type: "text",
      }),
      { params: makeParams("q-nonexistent") },
    );
    expect(res.status).toBe(404);
  });
});

// ─── DELETE /api/dashboard/reviews/questions/[questionId] ───────────────────

describe("DELETE /api/dashboard/reviews/questions/[questionId]", () => {
  let mod: typeof import("@/app/api/dashboard/reviews/questions/[templateId]/route");
  beforeAll(async () => {
    mod =
      await import("@/app/api/dashboard/reviews/questions/[templateId]/route");
  });
  beforeEach(() => jest.clearAllMocks());

  const makeParams = (templateId: string) => Promise.resolve({ templateId });

  it("returns 401 when unauthenticated", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(null);
    const res = await mod.DELETE(
      makeReq("/api/dashboard/reviews/questions/q1", "DELETE"),
      { params: makeParams("q1") },
    );
    expect(res.status).toBe(401);
  });

  it("deletes a question by ID", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(EXISTING_TEMPLATE);
    (mockDb.review_question_templates.update as jest.Mock).mockResolvedValue(
      EXISTING_TEMPLATE,
    );

    const res = await mod.DELETE(
      makeReq("/api/dashboard/reviews/questions/q1", "DELETE"),
      { params: makeParams("q1") },
    );
    expect(res.status).toBe(200);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(mockDb.review_question_templates.update).toHaveBeenCalled();
  });

  it("returns 404 when template not found", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(null);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(null);

    const res = await mod.DELETE(
      makeReq("/api/dashboard/reviews/questions/q1", "DELETE"),
      { params: makeParams("q1") },
    );
    expect(res.status).toBe(401);
  });

  it("returns 404 when question ID not found in template", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (
      mockDb.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(EXISTING_TEMPLATE);

    const res = await mod.DELETE(
      makeReq("/api/dashboard/reviews/questions/no-such-id", "DELETE"),
      { params: makeParams("no-such-id") },
    );
    expect(res.status).toBe(404);
  });
});

// ─── POST /api/dashboard/reviews/questions/generate ─────────────────────────

describe("POST /api/dashboard/reviews/questions/generate", () => {
  let mod: typeof import("@/app/api/dashboard/reviews/questions/generate/route");
  beforeAll(async () => {
    mod = await import("@/app/api/dashboard/reviews/questions/generate/route");
  });
  beforeEach(() => jest.clearAllMocks());

  it("returns 401 when unauthenticated", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(null);
    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions/generate", "POST", {
        industry: "healthcare",
        language: "en",
        count: 5,
      }),
    );
    expect(res.status).toBe(401);
  });

  it("returns AI-generated questions", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    const mockQuestions = [
      { questionEn: "How was the service?", questionAr: "كيف كانت الخدمة؟" },
      { questionEn: "Would you recommend us?", questionAr: "هل تنصح بنا؟" },
    ];
    (questionsService.generateReviewQuestions as jest.Mock).mockResolvedValue(
      mockQuestions,
    );

    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions/generate", "POST", {
        industry: "healthcare",
        language: "en",
        count: 5,
      }),
    );
    expect(res.status).toBe(200);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(json.questions).toEqual(mockQuestions);
    expect(questionsService.generateReviewQuestions).toHaveBeenCalledWith(
      "healthcare",
      "en",
      5,
    );
  });

  it("returns 400 for invalid language", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions/generate", "POST", {
        industry: "healthcare",
        language: "fr",
        count: 5,
      }),
    );
    expect(res.status).toBe(400);
  });

  it("returns 500 when AI generation fails", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (questionsService.generateReviewQuestions as jest.Mock).mockRejectedValue(
      new Error("API key missing"),
    );

    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/questions/generate", "POST", {
        industry: "healthcare",
        language: "en",
        count: 5,
      }),
    );
    expect(res.status).toBe(500);
  });
});
