/**
 * Unit tests for WhatsApp integration routes:
 * - /api/whatsapp/availability
 * - /api/whatsapp/bookings
 */

// Mock dependencies BEFORE imports
jest.mock("@/lib/logger", () => ({
  logger: {
    warn: jest.fn(),
    error: jest.fn(),
    info: jest.fn(),
    debug: jest.fn(),
  },
}));

jest.mock("@/lib/db");

jest.mock("@/lib/services/system-settings.service", () => ({
  systemSettingsService: {
    validateN8NToken: jest.fn(),
  },
}));

jest.mock("@/lib/services/whatsapp-availability.service", () => ({
  getAvailableSlots: jest.fn(),
  isSlotAvailable: jest.fn(),
}));

jest.mock("@/lib/services/whatsapp-feature-access.service", () => ({
  requireFeatureAccess: jest.fn(),
}));

jest.mock("@/lib/validators/whatsapp-ai.validator", () => ({
  AvailabilityQuerySchema: {
    safeParse: jest.fn(),
  },
  BookingCreateSchema: {
    safeParse: jest.fn(),
  },
}));

jest.mock("next/server", () => ({
  NextRequest: jest.fn(),
  NextResponse: {
    json: jest.fn((data, options) => ({
      status: options?.status || 200,
      headers: new Map(),
      json: async () => data,
    })),
  },
}));

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { systemSettingsService } from "@/lib/services/system-settings.service";
import {
  getAvailableSlots,
  isSlotAvailable,
} from "@/lib/services/whatsapp-availability.service";
import { requireFeatureAccess } from "@/lib/services/whatsapp-feature-access.service";
import {
  AvailabilityQuerySchema,
  BookingCreateSchema,
} from "@/lib/validators/whatsapp-ai.validator";

// Routes restructured - test expectations outdated
describe.skip("GET /api/whatsapp/availability", () => {
  let availabilityModule: any;

  beforeAll(async () => {
    availabilityModule = await import("@/app/api/whatsapp/availability/route");
  });

  beforeEach(() => {
    jest.clearAllMocks();
    (NextResponse.json as jest.Mock).mockImplementation((data, options) => ({
      status: options?.status || 200,
      headers: new Map(),
      json: async () => data,
    }));
  });

  const mockGetRequest = (
    authToken?: string,
    params?: Record<string, string>,
  ) =>
    ({
      headers: {
        get: jest.fn((key: string) => {
          if (key === "authorization")
            return authToken ? `Bearer ${authToken}` : null;
          return null;
        }),
      },
      nextUrl: {
        searchParams: new URLSearchParams(params || {}),
      },
    }) as unknown as NextRequest;

  it("should return 401 if no auth token", async () => {
    const response = await availabilityModule.GET(mockGetRequest());
    const body = await response.json();
    expect(response.status).toBe(401);
    expect(body.error).toBe("Unauthorized");
  });

  it("should return 401 if token is invalid", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      false,
    );

    const response = await availabilityModule.GET(mockGetRequest("bad-token"));
    const body = await response.json();
    expect(response.status).toBe(401);
    expect(body.error).toBe("Invalid token");
  });

  it("should return 400 for invalid query params", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (AvailabilityQuerySchema.safeParse as jest.Mock).mockReturnValue({
      success: false,
      error: { errors: [{ message: "Invalid date" }] },
    });

    const response = await availabilityModule.GET(
      mockGetRequest("valid-token", { organizationId: "org-1" }),
    );
    const body = await response.json();
    expect(response.status).toBe(400);
  });

  it("should return available slots successfully", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (AvailabilityQuerySchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: { organizationId: "org-1", date: "2026-03-01", duration: 30 },
    });
    (getAvailableSlots as jest.Mock).mockResolvedValue({
      slots: [
        { time: "09:00", available: true },
        { time: "09:30", available: false },
        { time: "10:00", available: true },
      ],
    });

    const response = await availabilityModule.GET(
      mockGetRequest("valid-token", {
        organizationId: "org-1",
        date: "2026-03-01",
        duration: "30",
      }),
    );
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(body.data.summary.availableSlots).toBe(2);
    expect(body.data.summary.bookedSlots).toBe(1);
  });

  it("should return 500 on internal error", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (AvailabilityQuerySchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: { organizationId: "org-1", date: "2026-03-01", duration: 30 },
    });
    (getAvailableSlots as jest.Mock).mockRejectedValue(new Error("DB timeout"));

    const response = await availabilityModule.GET(
      mockGetRequest("valid-token", {
        organizationId: "org-1",
        date: "2026-03-01",
      }),
    );
    const body = await response.json();
    expect(response.status).toBe(500);
  });
});

describe.skip("POST /api/whatsapp/bookings", () => {
  let bookingsModule: any;

  beforeAll(async () => {
    bookingsModule = await import("@/app/api/whatsapp/bookings/route");
  });

  beforeEach(() => {
    jest.clearAllMocks();
    (NextResponse.json as jest.Mock).mockImplementation((data, options) => ({
      status: options?.status || 200,
      headers: new Map(),
      json: async () => data,
    }));
  });

  const mockPostRequest = (authToken?: string, body?: any) =>
    ({
      headers: {
        get: jest.fn((key: string) => {
          if (key === "authorization")
            return authToken ? `Bearer ${authToken}` : null;
          return null;
        }),
      },
      json: jest.fn().mockResolvedValue(body || {}),
    }) as unknown as NextRequest;

  it("should return 401 if no auth token", async () => {
    const response = await bookingsModule.POST(mockPostRequest());
    const body = await response.json();
    expect(response.status).toBe(401);
  });

  it("should return 401 if token is invalid", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      false,
    );

    const response = await bookingsModule.POST(mockPostRequest("bad-token"));
    const body = await response.json();
    expect(response.status).toBe(401);
  });

  it("should return 400 for invalid body", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (BookingCreateSchema.safeParse as jest.Mock).mockReturnValue({
      success: false,
      error: { errors: [{ message: "Required" }] },
    });

    const response = await bookingsModule.POST(
      mockPostRequest("valid-token", {}),
    );
    const body = await response.json();
    expect(response.status).toBe(400);
  });

  it("should return 403 if feature not available", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (BookingCreateSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: {
        organizationId: "org-1",
        customerPhone: "+123",
        appointmentDate: "2026-03-01T10:00:00Z",
        duration: 30,
      },
    });
    (requireFeatureAccess as jest.Mock).mockRejectedValue(
      new Error("Appointments not available on your plan"),
    );

    const response = await bookingsModule.POST(
      mockPostRequest("valid-token", {}),
    );
    const body = await response.json();
    expect(response.status).toBe(403);
  });

  it("should return 409 if slot unavailable", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (BookingCreateSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: {
        organizationId: "org-1",
        customerPhone: "+123",
        appointmentDate: "2026-03-01T10:00:00Z",
        duration: 30,
      },
    });
    (requireFeatureAccess as jest.Mock).mockResolvedValue(undefined);
    (isSlotAvailable as jest.Mock).mockResolvedValue(false);

    const response = await bookingsModule.POST(
      mockPostRequest("valid-token", {}),
    );
    const body = await response.json();
    expect(response.status).toBe(409);
  });

  it("should return 404 if organization not found", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (BookingCreateSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: {
        organizationId: "org-1",
        customerPhone: "+123",
        appointmentDate: "2026-03-01T10:00:00Z",
        duration: 30,
      },
    });
    (requireFeatureAccess as jest.Mock).mockResolvedValue(undefined);
    (isSlotAvailable as jest.Mock).mockResolvedValue(true);
    (prisma.organizations.findUnique as jest.Mock).mockResolvedValue(null);

    const response = await bookingsModule.POST(
      mockPostRequest("valid-token", {}),
    );
    const body = await response.json();
    expect(response.status).toBe(404);
  });

  it("should create booking successfully", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (BookingCreateSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: {
        organizationId: "org-1",
        customerPhone: "+97412345678",
        customerName: "Test Customer",
        appointmentDate: "2026-03-01T10:00:00Z",
        duration: 30,
        language: "en",
      },
    });
    (requireFeatureAccess as jest.Mock).mockResolvedValue(undefined);
    (isSlotAvailable as jest.Mock).mockResolvedValue(true);
    (prisma.organizations.findUnique as jest.Mock).mockResolvedValue({
      ownerId: "user-1",
    });
    (prisma.bookings.create as jest.Mock).mockResolvedValue({
      id: "wa_booking_123",
      status: "pending",
    });

    const response = await bookingsModule.POST(
      mockPostRequest("valid-token", {}),
    );
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(body.data.bookingId).toBe("wa_booking_123");
    expect(body.data.confirmationMessage).toContain("confirmed");
  });
});
