/**
 * @jest-environment node
 */

/**
 * E2E Use Case Tests for the Review System
 *
 * Tests complete flows through multiple API routes (mock DB but test the flow).
 * Use Case 1: Manual review request flow
 * Use Case 2: Auto-trigger flow
 * Use Case 3: Bulk request flow
 * Use Case 4: AI question management
 * Use Case 5: Widget branding
 */

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(),
  submitReviewViaToken: jest.fn(),
  createReview: jest.fn(),
  listReviews: jest.fn(),
  getReviewStats: jest.fn(),
  getReviewRequestStats: jest.fn(),
}));
jest.mock("@/lib/services/review-widget.service", () => ({
  listFeaturedReviews: jest.fn(),
  toggleFeaturedReview: jest.fn(),
  reorderFeaturedReviews: jest.fn(),
  generateEmbedCode: jest.fn(),
  getWidgetSettings: jest.fn(),
  upsertWidgetSettings: jest.fn(),
}));
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/services/review-auto-trigger.service", () => ({
  processAutoReviewRequests: jest.fn(),
}));
jest.mock("@/lib/services/review-reminder.service", () => ({
  processReviewReminders: jest.fn(),
  expireStaleRequests: jest.fn(),
}));
jest.mock("@/lib/queue/email-queue", () => ({
  queueEmail: jest.fn(),
}));
jest.mock("@paralleldrive/cuid2", () => ({ createId: () => "test-cuid-e2e" }));
jest.mock("@/lib/db", () => ({
  prisma: {
    review_requests: { findFirst: jest.fn() },
    reviews: { update: jest.fn() },
    review_widget_settings: { findUnique: jest.fn().mockResolvedValue(null) },
    review_question_templates: {
      findUnique: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
    },
  },
}));

jest.mock("@/lib/email/review-request-email", () => ({
  buildReviewRequestEmailHtml: jest.fn().mockReturnValue({
    subject: "We'd love your feedback!",
    html: "<html>test</html>",
    text: "Leave a review",
  }),
}));
jest.mock("@/lib/logger", () => ({
  logger: {
    scope: () => ({
      info: jest.fn(),
      error: jest.fn(),
      warn: jest.fn(),
      debug: jest.fn(),
    }),
  },
}));

import { NextRequest } from "next/server";
import { getAuthenticatedUser } from "@/lib/utils/auth-helpers.util";
import * as reviewsService from "@/lib/services/reviews.service";
import * as widgetService from "@/lib/services/review-widget.service";
import * as questionsService from "@/lib/services/review-questions.service";
import * as autoTriggerService from "@/lib/services/review-auto-trigger.service";
import * as reminderService from "@/lib/services/review-reminder.service";
import { queueEmail } from "@/lib/queue/email-queue";
import { prisma } from "@/lib/db";

const mockUser = { userId: "biz-owner-1", email: "owner@clinic.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);
}

function makeCronRequest(url: string, method = "GET") {
  return new Request(`http://localhost:9000${url}`, {
    method,
    headers: { authorization: `Bearer ${process.env.CRON_SECRET}` },
  });
}

// ═══════════════════════════════════════════════════════════════════════════════
// Use Case 1: Manual Review Request Flow
// ═══════════════════════════════════════════════════════════════════════════════

describe.skip("Use Case 1: Manual review request flow", () => {
  let requestsRoute: typeof import("@/app/api/dashboard/reviews/requests/route");
  let sendRoute: typeof import("@/app/api/dashboard/reviews/requests/send/route");
  let publicReviewRoute: typeof import("@/app/api/public/review/[token]/route");
  let reviewsRoute: typeof import("@/app/api/dashboard/reviews/route");
  let testimonialsRoute: typeof import("@/app/api/dashboard/reviews/testimonials/route");
  let embedRoute: typeof import("@/app/api/dashboard/reviews/testimonials/embed/route");

  beforeAll(async () => {
    requestsRoute = await import("@/app/api/dashboard/reviews/requests/route");
    sendRoute = await import("@/app/api/dashboard/reviews/requests/send/route");
    publicReviewRoute = await import("@/app/api/public/review/[token]/route");
    reviewsRoute = await import("@/app/api/dashboard/reviews/route");
    testimonialsRoute =
      await import("@/app/api/dashboard/reviews/testimonials/route");
    embedRoute =
      await import("@/app/api/dashboard/reviews/testimonials/embed/route");
  });
  beforeEach(() => jest.clearAllMocks());

  it("complete flow: create request → send → customer submits → pin → embed", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);

    // Step 1: Business owner creates review request
    const mockReviewRequest = {
      id: "rreq-1",
      token: "abc123",
      customerName: "Alice",
      customerEmail: "alice@example.com",
      channel: "email",
      language: "en",
      status: "PENDING",
    };
    (reviewsService.createReviewRequest as jest.Mock).mockResolvedValue(
      mockReviewRequest,
    );

    const createRes = await requestsRoute.POST(
      makeReq("/api/dashboard/reviews/requests", "POST", {
        customerName: "Alice",
        customerEmail: "alice@example.com",
        channel: "email",
        language: "en",
      }),
    );
    expect(createRes.status).toBe(201);
    const createJson = await createRes.json();
    expect(createJson.success).toBe(true);
    expect(createJson.reviewRequest.token).toBe("abc123");

    // Step 2: Send the review request
    const sentRequest = { ...mockReviewRequest, status: "SENT" };
    (reviewsService.sendReviewRequest as jest.Mock).mockResolvedValue(
      sentRequest,
    );
    (queueEmail as jest.Mock).mockResolvedValue(undefined);

    const sendRes = await sendRoute.POST(
      makeReq("/api/dashboard/reviews/requests/send", "POST", {
        requestId: "rreq-1",
      }),
    );
    expect(sendRes.status).toBe(200);
    const sendJson = await sendRes.json();
    expect(sendJson.success).toBe(true);
    expect(sendJson.emailQueued).toBe(true);

    // Step 3: Customer opens review link
    (prisma.review_requests.findFirst as jest.Mock).mockResolvedValue({
      id: "rreq-1",
      customerName: "Alice",
      language: "en",
      userId: "biz-owner-1",
      questions: [],
    });
    (widgetService.getWidgetSettings as jest.Mock).mockResolvedValue(null);

    const publicGetRes = await publicReviewRoute.GET(
      makeReq("/api/public/review/abc123"),
      { params: Promise.resolve({ token: "abc123" }) },
    );
    expect(publicGetRes.status).toBe(200);
    const publicGetJson = await publicGetRes.json();
    expect(publicGetJson.customerName).toBe("Alice");

    // Step 4: Customer submits review
    const submittedReview = {
      id: "rev-1",
      rating: 5,
      title: "Excellent!",
      content: "Very professional",
      customerName: "Alice",
    };
    (reviewsService.submitReviewViaToken as jest.Mock).mockResolvedValue(
      submittedReview,
    );

    const submitRes = await publicReviewRoute.POST(
      makeReq("/api/public/review/abc123", "POST", {
        rating: 5,
        title: "Excellent!",
        content: "Very professional",
        customerName: "Alice",
        language: "en",
      }),
      { params: Promise.resolve({ token: "abc123" }) },
    );
    expect(submitRes.status).toBe(201);

    // Step 5: Review appears in business dashboard
    (reviewsService.listReviews as jest.Mock).mockResolvedValue({
      reviews: [submittedReview],
      total: 1,
      page: 1,
      limit: 20,
    });

    const listRes = await reviewsRoute.GET(makeReq("/api/dashboard/reviews"));
    expect(listRes.status).toBe(200);
    const listJson = await listRes.json();
    expect(listJson.reviews).toHaveLength(1);
    expect(listJson.reviews[0].customerName).toBe("Alice");

    // Step 6: Business pins as testimonial
    const pinnedReview = {
      ...submittedReview,
      featured: true,
      featuredOrder: 0,
    };
    (widgetService.toggleFeaturedReview as jest.Mock).mockResolvedValue(
      pinnedReview,
    );

    const pinRes = await testimonialsRoute.POST(
      makeReq("/api/dashboard/reviews/testimonials", "POST", {
        reviewId: "rev-1",
        featured: true,
      }),
    );
    expect(pinRes.status).toBe(200);
    const pinJson = await pinRes.json();
    expect(pinJson.review.featured).toBe(true);

    // Step 7: Embed code generated
    const embedHtml =
      '<iframe src="https://mawidi.com/embed/testimonials/biz-owner-1"></iframe>';
    (widgetService.generateEmbedCode as jest.Mock).mockResolvedValue(embedHtml);

    const embedRes = await embedRoute.GET(
      makeReq("/api/dashboard/reviews/testimonials/embed"),
    );
    expect(embedRes.status).toBe(200);
    const embedJson = await embedRes.json();
    expect(embedJson.embedCode).toContain("iframe");
  });
});

// ═══════════════════════════════════════════════════════════════════════════════
// Use Case 2: Auto-Trigger Flow
// ═══════════════════════════════════════════════════════════════════════════════

describe.skip("Use Case 2: Auto-trigger flow", () => {
  let autoSendRoute: typeof import("@/app/api/cron/review-auto-send/route");
  let remindersRoute: typeof import("@/app/api/cron/review-reminders/route");

  const originalEnv = process.env.CRON_SECRET;

  beforeAll(async () => {
    process.env.CRON_SECRET = "test-cron-secret";
    autoSendRoute = await import("@/app/api/cron/review-auto-send/route");
    remindersRoute = await import("@/app/api/cron/review-reminders/route");
  });
  afterAll(() => {
    process.env.CRON_SECRET = originalEnv;
  });
  beforeEach(() => jest.clearAllMocks());

  it("booking completed → auto-send cron → reminders → second reminder", async () => {
    // Step 1-2: Cron fires and auto-creates review requests
    (
      autoTriggerService.processAutoReviewRequests as jest.Mock
    ).mockResolvedValue({
      processed: 3,
      sent: 3,
      failed: 0,
      sources: ["auto_booking"],
    });

    const autoSendRes = await autoSendRoute.GET(
      makeCronRequest("/api/cron/review-auto-send"),
    );
    expect(autoSendRes.status).toBe(200);
    const autoSendJson = await autoSendRes.json();
    expect(autoSendJson.success).toBe(true);
    expect(autoSendJson.processed).toBe(3);

    // Step 3: After 3 days, reminder cron fires
    (reminderService.processReviewReminders as jest.Mock).mockResolvedValue({
      sent: 2,
      skipped: 1,
      reminderCounts: { 1: 2 },
    });
    (reminderService.expireStaleRequests as jest.Mock).mockResolvedValue({
      expired: 0,
    });

    const reminder1Res = await remindersRoute.GET(
      makeCronRequest("/api/cron/review-reminders"),
    );
    expect(reminder1Res.status).toBe(200);
    const reminder1Json = await reminder1Res.json();
    expect(reminder1Json.reminders.sent).toBe(2);

    // Step 4: After 7 more days, second reminder + some expire
    (reminderService.processReviewReminders as jest.Mock).mockResolvedValue({
      sent: 1,
      skipped: 1,
      reminderCounts: { 2: 1 },
    });
    (reminderService.expireStaleRequests as jest.Mock).mockResolvedValue({
      expired: 1,
    });

    const reminder2Res = await remindersRoute.GET(
      makeCronRequest("/api/cron/review-reminders"),
    );
    expect(reminder2Res.status).toBe(200);
    const reminder2Json = await reminder2Res.json();
    expect(reminder2Json.reminders.sent).toBe(1);
    expect(reminder2Json.expired.expired).toBe(1);
  });
});

// ═══════════════════════════════════════════════════════════════════════════════
// Use Case 3: Bulk Request Flow
// ═══════════════════════════════════════════════════════════════════════════════

describe.skip("Use Case 3: Bulk request flow", () => {
  let bulkRoute: typeof import("@/app/api/dashboard/reviews/requests/bulk/route");
  let statsRoute: typeof import("@/app/api/dashboard/reviews/stats/route");

  beforeAll(async () => {
    bulkRoute = await import("@/app/api/dashboard/reviews/requests/bulk/route");
    statsRoute = await import("@/app/api/dashboard/reviews/stats/route");
  });
  beforeEach(() => jest.clearAllMocks());

  it("bulk create 5 requests → 3 complete → 60% rate", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);

    // Step 1-2: Business sends 5 bulk requests
    let callIdx = 0;
    (reviewsService.createReviewRequest as jest.Mock).mockImplementation(() => {
      callIdx++;
      return Promise.resolve({
        id: `rreq-${callIdx}`,
        token: `bulk-tok-${callIdx}`,
        customerName: `Customer ${callIdx}`,
        customerEmail: `c${callIdx}@test.com`,
        channel: "email",
        language: "en",
      });
    });
    (reviewsService.sendReviewRequest as jest.Mock).mockResolvedValue(
      undefined,
    );
    (queueEmail as jest.Mock).mockResolvedValue(undefined);

    const bulkRes = await bulkRoute.POST(
      makeReq("/api/dashboard/reviews/requests/bulk", "POST", {
        requests: [
          {
            customerName: "C1",
            customerEmail: "c1@test.com",
            channel: "email",
          },
          {
            customerName: "C2",
            customerEmail: "c2@test.com",
            channel: "email",
          },
          {
            customerName: "C3",
            customerEmail: "c3@test.com",
            channel: "email",
          },
          {
            customerName: "C4",
            customerEmail: "c4@test.com",
            channel: "email",
          },
          {
            customerName: "C5",
            customerEmail: "c5@test.com",
            channel: "email",
          },
        ],
        language: "en",
      }),
    );
    expect(bulkRes.status).toBe(201);
    const bulkJson = await bulkRes.json();
    expect(bulkJson.total).toBe(5);
    expect(bulkJson.sent).toBe(5);
    expect(reviewsService.createReviewRequest).toHaveBeenCalledTimes(5);
    expect(queueEmail).toHaveBeenCalledTimes(5);

    // Step 3-4: Check stats show 60% completion (3 of 5 completed)
    (reviewsService.getReviewStats as jest.Mock).mockResolvedValue({
      totalReviews: 3,
      averageRating: 4.3,
      ratingDistribution: { 5: 1, 4: 1, 3: 1 },
    });
    (reviewsService.getReviewRequestStats as jest.Mock).mockResolvedValue({
      totalRequests: 5,
      completed: 3,
      pending: 2,
      completionRate: 0.6,
    });

    const statsRes = await statsRoute.GET(
      makeReq("/api/dashboard/reviews/stats"),
    );
    expect(statsRes.status).toBe(200);
    const statsJson = await statsRes.json();
    expect(statsJson.requestStats.completionRate).toBe(0.6);
    expect(statsJson.requestStats.completed).toBe(3);
    expect(statsJson.requestStats.totalRequests).toBe(5);
  });
});

// ═══════════════════════════════════════════════════════════════════════════════
// Use Case 4: AI Question Management
// ═══════════════════════════════════════════════════════════════════════════════

describe.skip("Use Case 4: AI question management", () => {
  let generateRoute: typeof import("@/app/api/dashboard/reviews/questions/generate/route");
  let questionsRoute: typeof import("@/app/api/dashboard/reviews/questions/route");
  let templateRoute: typeof import("@/app/api/dashboard/reviews/questions/[templateId]/route");

  beforeAll(async () => {
    generateRoute =
      await import("@/app/api/dashboard/reviews/questions/generate/route");
    questionsRoute =
      await import("@/app/api/dashboard/reviews/questions/route");
    templateRoute =
      await import("@/app/api/dashboard/reviews/questions/[templateId]/route");
  });
  beforeEach(() => jest.clearAllMocks());

  it("generate healthcare questions in both languages → edit → save template", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);

    // Step 1: Generate questions for healthcare in English
    const generatedEn = [
      {
        questionEn: "How would you rate the doctor?",
        questionAr: "كيف تقيم الطبيب؟",
      },
      {
        questionEn: "Was the wait time acceptable?",
        questionAr: "هل كان وقت الانتظار مقبولاً؟",
      },
      {
        questionEn: "Would you recommend our clinic?",
        questionAr: "هل تنصح بعيادتنا؟",
      },
    ];
    (questionsService.generateReviewQuestions as jest.Mock).mockResolvedValue(
      generatedEn,
    );

    const genRes = await generateRoute.POST(
      makeReq("/api/dashboard/reviews/questions/generate", "POST", {
        industry: "healthcare",
        language: "en",
        count: 3,
      }),
    );
    expect(genRes.status).toBe(200);
    const genJson = await genRes.json();
    expect(genJson.questions).toHaveLength(3);
    expect(genJson.questions[0].questionEn).toContain("doctor");
    expect(genJson.questions[0].questionAr).toBeDefined();

    // Step 2: Generate in Arabic too
    const generatedAr = [
      {
        questionEn: "How clean was the facility?",
        questionAr: "ما مدى نظافة المنشأة؟",
      },
    ];
    (questionsService.generateReviewQuestions as jest.Mock).mockResolvedValue(
      generatedAr,
    );

    const genArRes = await generateRoute.POST(
      makeReq("/api/dashboard/reviews/questions/generate", "POST", {
        industry: "healthcare",
        language: "ar",
        count: 1,
      }),
    );
    expect(genArRes.status).toBe(200);

    // Step 3: Add a custom question using the flat questions API
    const existingTemplate = {
      id: "tpl-general-1",
      userId: "biz-owner-1",
      industry: "general",
      isDefault: true,
      questions: [
        {
          id: "q1",
          questionEn: "How was your experience?",
          questionAr: "كيف كانت تجربتك؟",
          type: "rating",
          sortOrder: 0,
        },
      ],
      createdAt: new Date(),
      updatedAt: new Date(),
    };
    const { prisma: mockPrisma } = await import("@/lib/db");
    (
      mockPrisma.review_question_templates.findUnique as jest.Mock
    ).mockResolvedValue(existingTemplate);
    (
      mockPrisma.review_question_templates.update as jest.Mock
    ).mockResolvedValue(existingTemplate);

    const saveRes = await questionsRoute.POST(
      makeReq("/api/dashboard/reviews/questions", "POST", {
        questionEn: "How was your overall experience?",
        questionAr: "كيف كانت تجربتك العامة؟",
        type: "rating",
      }),
    );
    expect(saveRes.status).toBe(201);
    const saveJson = await saveRes.json();
    expect(saveJson.question.questionEn).toBe(
      "How was your overall experience?",
    );
    expect(saveJson.question.type).toBe("rating");

    // Step 4: Update an existing question with custom edits
    const updateRes = await templateRoute.PUT(
      makeReq("/api/dashboard/reviews/questions/q1", "PUT", {
        questionEn: "Rate your overall experience",
        questionAr: "قيم تجربتك العامة",
        type: "rating",
      }),
      { params: Promise.resolve({ templateId: "q1" }) },
    );
    expect(updateRes.status).toBe(200);
    const updateJson = await updateRes.json();
    expect(updateJson.question.questionEn).toBe("Rate your overall experience");
  });
});

// ═══════════════════════════════════════════════════════════════════════════════
// Use Case 5: Widget Branding
// ═══════════════════════════════════════════════════════════════════════════════

describe.skip("Use Case 5: Widget branding", () => {
  let widgetSettingsRoute: typeof import("@/app/api/dashboard/reviews/widget-settings/route");
  let publicReviewRoute: typeof import("@/app/api/public/review/[token]/route");
  let publicTestimonialsRoute: typeof import("@/app/api/public/testimonials/[userId]/route");

  beforeAll(async () => {
    widgetSettingsRoute =
      await import("@/app/api/dashboard/reviews/widget-settings/route");
    publicReviewRoute = await import("@/app/api/public/review/[token]/route");
    publicTestimonialsRoute =
      await import("@/app/api/public/testimonials/[userId]/route");
  });
  beforeEach(() => jest.clearAllMocks());

  it("configure branding → public page uses it → embed shows branding", async () => {
    (getAuthenticatedUser as jest.Mock).mockResolvedValue(mockUser);

    // Step 1: Business configures widget settings
    const brandSettings = {
      businessName: "Dr. Ahmad's Clinic",
      businessNameAr: "عيادة د. أحمد",
      logoUrl: "https://cdn.mawidi.com/logos/clinic.png",
      primaryColor: "#0ea5e9",
      backgroundColor: "#f0f9ff",
      textColor: "#0c4a6e",
      thankYouMessage: "Thank you for your review!",
      thankYouMessageAr: "شكرًا لتقييمك!",
      showPoweredBy: false,
    };
    (widgetService.upsertWidgetSettings as jest.Mock).mockResolvedValue(
      brandSettings,
    );

    const settingsRes = await widgetSettingsRoute.PUT(
      makeReq("/api/dashboard/reviews/widget-settings", "PUT", brandSettings),
    );
    expect(settingsRes.status).toBe(200);
    const settingsJson = await settingsRes.json();
    expect(settingsJson.settings.primaryColor).toBe("#0ea5e9");
    expect(settingsJson.settings.businessNameAr).toBe("عيادة د. أحمد");

    // Step 2: Public review page renders with custom branding
    (prisma.review_requests.findFirst as jest.Mock).mockResolvedValue({
      id: "rreq-brand",
      customerName: "Sara",
      language: "en",
      userId: "biz-owner-1",
      questions: [],
    });
    (widgetService.getWidgetSettings as jest.Mock).mockResolvedValue(
      brandSettings,
    );

    const publicRes = await publicReviewRoute.GET(
      makeReq("/api/public/review/brand-token"),
      { params: Promise.resolve({ token: "brand-token" }) },
    );
    expect(publicRes.status).toBe(200);
    const publicJson = await publicRes.json();
    expect(publicJson.widgetSettings.primaryColor).toBe("#0ea5e9");
    expect(publicJson.widgetSettings.logoUrl).toContain("clinic.png");
    expect(publicJson.widgetSettings.businessName).toBe("Dr. Ahmad's Clinic");

    // Step 3: Embed widget shows featured testimonials with branding
    const featuredReviews = [
      {
        id: "r1",
        customerName: "Alice",
        rating: 5,
        content: "Amazing clinic!",
      },
      { id: "r2", customerName: "فاطمة", rating: 5, content: "عيادة ممتازة!" },
    ];
    (widgetService.listFeaturedReviews as jest.Mock).mockResolvedValue(
      featuredReviews,
    );

    const embedRes = await publicTestimonialsRoute.GET(
      makeReq("/api/public/testimonials/biz-owner-1"),
      { params: Promise.resolve({ userId: "biz-owner-1" }) },
    );
    expect(embedRes.status).toBe(200);
    const embedJson = await embedRes.json();
    expect(embedJson.reviews).toHaveLength(2);
    expect(embedJson.reviews[0].customerName).toBe("Alice");
    expect(embedJson.reviews[1].customerName).toBe("فاطمة");
    // CORS headers present for embedding
    expect(embedRes.headers.get("Access-Control-Allow-Origin")).toBe("*");
  });
});
