/**
 * Tests for public review submission API (NO AUTH)
 * GET/POST /api/public/review/[token]
 */

jest.mock("@/lib/db");
jest.mock("@/lib/services/reviews.service", () => ({
  submitReviewViaToken: jest.fn(),
}));
jest.mock("@/lib/services/review-widget.service", () => ({
  getWidgetSettings: jest.fn(),
}));
jest.mock("@/lib/logger", () => ({
  logger: {
    scope: () => ({
      info: jest.fn(),
      error: jest.fn(),
      warn: jest.fn(),
      debug: jest.fn(),
    }),
  },
}));

import { NextRequest } from "next/server";
import { prisma } from "@/lib/db";
import * as reviewsService from "@/lib/services/reviews.service";
import * as widgetService from "@/lib/services/review-widget.service";

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/public/review/[token] ─────────────────────────────────────────

describe("GET /api/public/review/[token]", () => {
  let mod: typeof import("@/app/api/public/review/[token]/route");
  beforeAll(async () => {
    mod = await import("@/app/api/public/review/[token]/route");
  });
  beforeEach(() => jest.clearAllMocks());

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

  it("returns questions and widget data for valid token", async () => {
    const mockRequest = {
      id: "req-1",
      customerName: "Alice",
      language: "en",
      userId: "user-1",
      questions: [{ questionEn: "How was it?", questionAr: "كيف كانت؟" }],
    };
    (prisma.review_requests.findFirst as jest.Mock).mockResolvedValue(
      mockRequest,
    );

    const mockWidget = { primaryColor: "#10b981", businessName: "Test Clinic" };
    (widgetService.getWidgetSettings as jest.Mock).mockResolvedValue(
      mockWidget,
    );

    const res = await mod.GET(makeReq("/api/public/review/valid-token"), {
      params: makeParams("valid-token"),
    });
    expect(res.status).toBe(200);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(json.customerName).toBe("Alice");
    expect(json.language).toBe("en");
    expect(json.questions).toHaveLength(1);
    expect(json.widgetSettings).toEqual(mockWidget);
  });

  it("returns 404 for expired token", async () => {
    (prisma.review_requests.findFirst as jest.Mock).mockResolvedValue(null);

    const res = await mod.GET(makeReq("/api/public/review/expired-token"), {
      params: makeParams("expired-token"),
    });
    expect(res.status).toBe(404);
    const json = await res.json();
    expect(json.error).toBe("Invalid or expired review link");
  });

  it("returns 404 for invalid token", async () => {
    (prisma.review_requests.findFirst as jest.Mock).mockResolvedValue(null);

    const res = await mod.GET(makeReq("/api/public/review/nonexistent"), {
      params: makeParams("nonexistent"),
    });
    expect(res.status).toBe(404);
  });

  it("still returns data when widget settings fail to load", async () => {
    const mockRequest = {
      id: "req-1",
      customerName: "Bob",
      language: "ar",
      userId: "user-1",
      questions: [],
    };
    (prisma.review_requests.findFirst as jest.Mock).mockResolvedValue(
      mockRequest,
    );
    (widgetService.getWidgetSettings as jest.Mock).mockRejectedValue(
      new Error("DB error"),
    );

    const res = await mod.GET(makeReq("/api/public/review/valid-token"), {
      params: makeParams("valid-token"),
    });
    expect(res.status).toBe(200);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(json.widgetSettings).toBeNull();
  });

  it("returns empty questions array when none configured", async () => {
    const mockRequest = {
      id: "req-1",
      customerName: "Charlie",
      language: "en",
      userId: "user-1",
      questions: null,
    };
    (prisma.review_requests.findFirst as jest.Mock).mockResolvedValue(
      mockRequest,
    );
    (widgetService.getWidgetSettings as jest.Mock).mockResolvedValue(null);

    const res = await mod.GET(makeReq("/api/public/review/some-token"), {
      params: makeParams("some-token"),
    });
    const json = await res.json();
    expect(json.questions).toEqual([]);
  });
});

// ─── POST /api/public/review/[token] ────────────────────────────────────────

describe("POST /api/public/review/[token]", () => {
  let mod: typeof import("@/app/api/public/review/[token]/route");
  beforeAll(async () => {
    mod = await import("@/app/api/public/review/[token]/route");
  });
  beforeEach(() => jest.clearAllMocks());

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

  it("submits review with question responses", async () => {
    const mockReview = { id: "rev-1", rating: 5, customerName: "Alice" };
    (reviewsService.submitReviewViaToken as jest.Mock).mockResolvedValue(
      mockReview,
    );
    (prisma.reviews.update as jest.Mock).mockResolvedValue(mockReview);

    const res = await mod.POST(
      makeReq("/api/public/review/valid-token", "POST", {
        rating: 5,
        title: "Great service",
        content: "Really enjoyed my visit",
        customerName: "Alice",
        language: "en",
        questionResponses: [
          { questionEn: "How was it?", answer: "Amazing", rating: 5 },
        ],
      }),
      { params: makeParams("valid-token") },
    );
    expect(res.status).toBe(201);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(json.review).toEqual(mockReview);
    expect(reviewsService.submitReviewViaToken).toHaveBeenCalledWith(
      "valid-token",
      {
        rating: 5,
        title: "Great service",
        content: "Really enjoyed my visit",
        customerName: "Alice",
        language: "en",
      },
    );
    expect(prisma.reviews.update).toHaveBeenCalled();
  });

  it("submits review without question responses", async () => {
    const mockReview = { id: "rev-2", rating: 4, customerName: "Bob" };
    (reviewsService.submitReviewViaToken as jest.Mock).mockResolvedValue(
      mockReview,
    );

    const res = await mod.POST(
      makeReq("/api/public/review/tok-2", "POST", {
        rating: 4,
        customerName: "Bob",
        language: "ar",
      }),
      { params: makeParams("tok-2") },
    );
    expect(res.status).toBe(201);
    const json = await res.json();
    expect(json.success).toBe(true);
    // No question responses, so reviews.update should not be called
    expect(prisma.reviews.update).not.toHaveBeenCalled();
  });

  it("returns 404 for expired token", async () => {
    (reviewsService.submitReviewViaToken as jest.Mock).mockResolvedValue(null);

    const res = await mod.POST(
      makeReq("/api/public/review/expired", "POST", {
        rating: 3,
        customerName: "Eve",
        language: "en",
      }),
      { params: makeParams("expired") },
    );
    expect(res.status).toBe(404);
    const json = await res.json();
    expect(json.error).toBe("Invalid or expired review link");
  });

  it("returns 400 for validation error — missing rating", async () => {
    const res = await mod.POST(
      makeReq("/api/public/review/tok-3", "POST", {
        customerName: "Test",
        language: "en",
      }),
      { params: makeParams("tok-3") },
    );
    expect(res.status).toBe(400);
    const json = await res.json();
    expect(json.success).toBe(false);
  });

  it("returns 400 for invalid rating value", async () => {
    const res = await mod.POST(
      makeReq("/api/public/review/tok-4", "POST", {
        rating: 6,
        customerName: "Test",
        language: "en",
      }),
      { params: makeParams("tok-4") },
    );
    expect(res.status).toBe(400);
  });

  it("submits review in Arabic", async () => {
    const mockReview = { id: "rev-ar", rating: 5, customerName: "أحمد" };
    (reviewsService.submitReviewViaToken as jest.Mock).mockResolvedValue(
      mockReview,
    );

    const res = await mod.POST(
      makeReq("/api/public/review/ar-tok", "POST", {
        rating: 5,
        title: "خدمة ممتازة",
        content: "تجربة رائعة",
        customerName: "أحمد",
        language: "ar",
      }),
      { params: makeParams("ar-tok") },
    );
    expect(res.status).toBe(201);
    expect(reviewsService.submitReviewViaToken).toHaveBeenCalledWith("ar-tok", {
      rating: 5,
      title: "خدمة ممتازة",
      content: "تجربة رائعة",
      customerName: "أحمد",
      language: "ar",
    });
  });
});
