/**
 * Tests for bulk review requests API route
 * POST /api/dashboard/reviews/requests/bulk
 */

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("@/lib/services/reviews.service", () => ({
  createReviewRequest: jest.fn(),
  sendReviewRequest: jest.fn(),
}));
jest.mock("@/lib/queue/email-queue", () => ({
  queueEmail: 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"),
}));
jest.mock("@/lib/validators/reviews.validator", () => ({
  BulkReviewRequestSchema: {
    safeParse: jest.fn((data: any) => {
      if (!data.requests || data.requests.length === 0) {
        return {
          success: false,
          error: {
            flatten: () => "Requests array is required and must not be empty",
          },
        };
      }
      return { success: true, data };
    }),
  },
}));

import { NextRequest } from "next/server";
import { getAuthenticatedUser } from "@/lib/utils/auth-helpers.util";
import * as reviewsService from "@/lib/services/reviews.service";
import { queueEmail } from "@/lib/queue/email-queue";

const mockUser = { userId: "user-1", email: "test@test.com" };

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);
}

describe("POST /api/dashboard/reviews/requests/bulk", () => {
  let mod: typeof import("@/app/api/dashboard/reviews/requests/bulk/route");
  beforeAll(async () => {
    mod = await import("@/app/api/dashboard/reviews/requests/bulk/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/requests/bulk", "POST", {
        requests: [
          { customerName: "Test", channel: "email", customerEmail: "a@b.com" },
        ],
      }),
    );
    expect(res.status).toBe(401);
  });

  it("creates bulk requests successfully", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);

    let callCount = 0;
    (reviewsService.createReviewRequest as jest.Mock).mockImplementation(() => {
      callCount++;
      return Promise.resolve({
        id: `req-${callCount}`,
        token: `tok-${callCount}`,
        customerName: `Customer ${callCount}`,
        customerEmail: `c${callCount}@test.com`,
        channel: "email",
        language: "en",
      });
    });
    (reviewsService.sendReviewRequest as jest.Mock).mockResolvedValue(
      undefined,
    );
    (queueEmail as jest.Mock).mockResolvedValue(undefined);

    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/requests/bulk", "POST", {
        requests: [
          {
            customerName: "Alice",
            customerEmail: "alice@test.com",
            channel: "email",
          },
          {
            customerName: "Bob",
            customerEmail: "bob@test.com",
            channel: "email",
          },
          {
            customerName: "Charlie",
            customerPhone: "+97412345678",
            channel: "whatsapp",
          },
        ],
        language: "en",
      }),
    );
    expect(res.status).toBe(201);
    const json = await res.json();
    expect(json.success).toBe(true);
    expect(json.total).toBe(3);
    expect(json.sent).toBe(3);
    expect(json.failed).toBe(0);
    expect(json.results).toHaveLength(3);
    expect(reviewsService.createReviewRequest).toHaveBeenCalledTimes(3);
    expect(reviewsService.sendReviewRequest).toHaveBeenCalledTimes(3);
  });

  it("returns 400 for empty requests array", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/requests/bulk", "POST", {
        requests: [],
        language: "en",
      }),
    );
    expect(res.status).toBe(400);
    const json = await res.json();
    expect(json.success).toBe(false);
  });

  it("handles mixed success/failure in bulk", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);

    let callIdx = 0;
    (reviewsService.createReviewRequest as jest.Mock).mockImplementation(() => {
      callIdx++;
      if (callIdx === 2) {
        return Promise.reject(new Error("Duplicate customer"));
      }
      return Promise.resolve({
        id: `req-${callIdx}`,
        token: `tok-${callIdx}`,
        customerName: `Customer ${callIdx}`,
        channel: "email",
        language: "en",
      });
    });
    (reviewsService.sendReviewRequest as jest.Mock).mockResolvedValue(
      undefined,
    );

    const res = await mod.POST(
      makeReq("/api/dashboard/reviews/requests/bulk", "POST", {
        requests: [
          {
            customerName: "Alice",
            customerEmail: "alice@test.com",
            channel: "email",
          },
          {
            customerName: "Bob",
            customerEmail: "bob@test.com",
            channel: "email",
          },
          {
            customerName: "Charlie",
            customerEmail: "charlie@test.com",
            channel: "email",
          },
        ],
        language: "en",
      }),
    );
    expect(res.status).toBe(201);
    const json = await res.json();
    expect(json.total).toBe(3);
    expect(json.sent).toBe(2);
    expect(json.failed).toBe(1);
    const failedResult = json.results.find(
      (r: { success: boolean }) => !r.success,
    );
    expect(failedResult).toBeDefined();
    expect(failedResult.customerName).toBe("Bob");
    expect(failedResult.error).toBe("Duplicate customer");
  });

  it("queues emails for email channel requests", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (reviewsService.createReviewRequest as jest.Mock).mockResolvedValue({
      id: "req-1",
      token: "tok-1",
      customerName: "Alice",
      customerEmail: "alice@test.com",
      channel: "email",
      language: "en",
    });
    (reviewsService.sendReviewRequest as jest.Mock).mockResolvedValue(
      undefined,
    );
    (queueEmail as jest.Mock).mockResolvedValue(undefined);

    await mod.POST(
      makeReq("/api/dashboard/reviews/requests/bulk", "POST", {
        requests: [
          {
            customerName: "Alice",
            customerEmail: "alice@test.com",
            channel: "email",
          },
        ],
        language: "en",
      }),
    );

    expect(queueEmail).toHaveBeenCalledTimes(1);
    expect(queueEmail).toHaveBeenCalledWith(
      expect.objectContaining({
        to: "alice@test.com",
        category: "review_request",
      }),
    );
  });

  it("sends Arabic emails when language is ar", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);
    (reviewsService.createReviewRequest as jest.Mock).mockResolvedValue({
      id: "req-1",
      token: "tok-1",
      customerName: "أحمد",
      customerEmail: "ahmed@test.com",
      channel: "email",
      language: "ar",
    });
    (reviewsService.sendReviewRequest as jest.Mock).mockResolvedValue(
      undefined,
    );
    (queueEmail as jest.Mock).mockResolvedValue(undefined);

    await mod.POST(
      makeReq("/api/dashboard/reviews/requests/bulk", "POST", {
        requests: [
          {
            customerName: "أحمد",
            customerEmail: "ahmed@test.com",
            channel: "email",
          },
        ],
        language: "ar",
      }),
    );

    expect(queueEmail).toHaveBeenCalledWith(
      expect.objectContaining({
        subject: "نود سماع رأيك!",
      }),
    );
  });
});
