/**
 * Unit tests for /api/webhooks/twilio-whatsapp
 * Tests Twilio WhatsApp webhook (GET health check, POST incoming messages)
 */

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

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

jest.mock("@/lib/services/twilio-whatsapp.service", () => ({
  twilioWhatsAppService: {
    getOrgByTwilioNumber: jest.fn(),
    getCredentialsForOrg: jest.fn(),
    validateSignature: jest.fn(),
    parseIncomingMessage: jest.fn(),
    sendTextMessage: jest.fn(),
  },
}));

jest.mock("@/lib/services/whatsapp-ai-engine.service", () => ({
  whatsAppAIEngine: {
    processMessage: jest.fn(),
  },
}));

jest.mock("@/lib/sanitizers/chat.sanitizer", () => ({
  sanitizeChatMessage: jest.fn((msg: string) => msg),
  sanitizePhoneNumber: jest.fn((phone: string) => phone),
}));

jest.mock("@/lib/services/whatsapp-language.service", () => ({
  getLanguagePreference: jest.fn(),
  setLanguagePreference: jest.fn(),
}));

jest.mock("@/lib/services/qatari-dialect.service", () => ({
  qatariDialectService: {
    translateToQatari: jest.fn(),
  },
}));

jest.mock("@upstash/ratelimit", () => ({
  Ratelimit: jest.fn().mockImplementation(() => ({
    limit: jest.fn().mockResolvedValue({
      success: true,
      limit: 100,
      remaining: 99,
      reset: Date.now() + 60000,
    }),
  })),
}));

jest.mock("@upstash/redis", () => ({
  Redis: jest.fn(),
}));

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

import { NextRequest, NextResponse } from "next/server";
import { twilioWhatsAppService } from "@/lib/services/twilio-whatsapp.service";
import { whatsAppAIEngine } from "@/lib/services/whatsapp-ai-engine.service";
import { prisma } from "@/lib/db";
import { getLanguagePreference } from "@/lib/services/whatsapp-language.service";

// Webhook route not yet implemented
describe.skip("Twilio WhatsApp Webhook", () => {
  let webhookModule: any;

  beforeAll(async () => {
    webhookModule = await import("@/app/api/webhooks/twilio-whatsapp/route");
  });

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

  describe("GET - Health check", () => {
    it("should return ok status", async () => {
      const response = await webhookModule.GET();
      const body = await response.json();
      expect(body.status).toBe("ok");
      expect(body.service).toBe("twilio-whatsapp-webhook");
    });
  });

  describe("POST - Incoming Messages", () => {
    const mockPostRequest = (body: string, signature?: string, ip?: string) =>
      ({
        text: jest.fn().mockResolvedValue(body),
        headers: {
          get: jest.fn((key: string) => {
            if (key === "x-twilio-signature") return signature || null;
            if (key === "x-forwarded-for") return ip || "1.2.3.4";
            if (key === "x-real-ip") return null;
            return null;
          }),
        },
        ip: ip || "1.2.3.4",
        url: "https://example.com/api/webhooks/twilio-whatsapp",
      }) as unknown as NextRequest;

    it("should return 200 empty for missing signature", async () => {
      const params = new URLSearchParams({
        To: "whatsapp:+97412345678",
        From: "whatsapp:+97498765432",
        Body: "Hello",
      });
      const response = await webhookModule.POST(
        mockPostRequest(params.toString()),
      );
      // Returns empty Response with 200 status
      expect(response.status).toBe(200);
    });

    it("should return 200 for unknown To number", async () => {
      const params = new URLSearchParams({
        To: "whatsapp:+97400000000",
        From: "whatsapp:+97498765432",
        Body: "Hello",
      });

      (
        twilioWhatsAppService.getOrgByTwilioNumber as jest.Mock
      ).mockResolvedValue(null);

      const response = await webhookModule.POST(
        mockPostRequest(params.toString(), "valid-sig"),
      );
      expect(response.status).toBe(200);
    });

    it("should return 200 for missing credentials", async () => {
      const params = new URLSearchParams({
        To: "whatsapp:+97412345678",
        From: "whatsapp:+97498765432",
        Body: "Hello",
      });

      (
        twilioWhatsAppService.getOrgByTwilioNumber as jest.Mock
      ).mockResolvedValue({
        id: "org-1",
        name: "Test Org",
      });
      (
        twilioWhatsAppService.getCredentialsForOrg as jest.Mock
      ).mockResolvedValue(null);

      const response = await webhookModule.POST(
        mockPostRequest(params.toString(), "valid-sig"),
      );
      expect(response.status).toBe(200);
    });

    it("should return 200 for invalid signature", async () => {
      const params = new URLSearchParams({
        To: "whatsapp:+97412345678",
        From: "whatsapp:+97498765432",
        Body: "Hello",
      });

      (
        twilioWhatsAppService.getOrgByTwilioNumber as jest.Mock
      ).mockResolvedValue({
        id: "org-1",
        name: "Test Org",
      });
      (
        twilioWhatsAppService.getCredentialsForOrg as jest.Mock
      ).mockResolvedValue({
        authToken: "token123",
      });
      (twilioWhatsAppService.validateSignature as jest.Mock).mockReturnValue(
        false,
      );

      const response = await webhookModule.POST(
        mockPostRequest(params.toString(), "invalid-sig"),
      );
      expect(response.status).toBe(200);
    });

    it("should process new conversation with bilingual greeting", async () => {
      const params = new URLSearchParams({
        To: "whatsapp:+97412345678",
        From: "whatsapp:+97498765432",
        Body: "Hello",
        ProfileName: "Test Customer",
      });

      (
        twilioWhatsAppService.getOrgByTwilioNumber as jest.Mock
      ).mockResolvedValue({
        id: "org-1",
        name: "Test Org",
      });
      (
        twilioWhatsAppService.getCredentialsForOrg as jest.Mock
      ).mockResolvedValue({
        authToken: "token123",
      });
      (twilioWhatsAppService.validateSignature as jest.Mock).mockReturnValue(
        true,
      );
      (twilioWhatsAppService.parseIncomingMessage as jest.Mock).mockReturnValue(
        {
          body: "Hello",
          from: "whatsapp:+97498765432",
          profileName: "Test Customer",
          messageSid: "SM123",
        },
      );
      // No existing conversation
      (
        prisma.org_whatsapp_conversations.findFirst as jest.Mock
      ).mockResolvedValue(null);
      (prisma.org_whatsapp_conversations.create as jest.Mock).mockResolvedValue(
        {
          id: "conv-1",
          organizationId: "org-1",
          userPhone: "+97498765432",
          conversationState: null,
          humanControlled: false,
          messageCount: 0,
        },
      );
      (getLanguagePreference as jest.Mock).mockResolvedValue(null);
      (prisma.org_whatsapp_messages.create as jest.Mock).mockResolvedValue({});
      (twilioWhatsAppService.sendTextMessage as jest.Mock).mockResolvedValue({
        success: true,
      });
      (prisma.org_whatsapp_conversations.update as jest.Mock).mockResolvedValue(
        {},
      );

      const response = await webhookModule.POST(
        mockPostRequest(params.toString(), "valid-sig"),
      );
      expect(response.status).toBe(200);
      // Should have sent bilingual greeting
      expect(twilioWhatsAppService.sendTextMessage).toHaveBeenCalled();
    });

    it("should handle errors gracefully (return 200)", async () => {
      const mockReq = {
        text: jest.fn().mockRejectedValue(new Error("Parse error")),
        headers: {
          get: jest.fn(() => null),
        },
        ip: "1.2.3.4",
        url: "https://example.com/api/webhooks/twilio-whatsapp",
      } as unknown as NextRequest;

      const response = await webhookModule.POST(mockReq);
      // Always returns 200 to prevent Twilio retries
      expect(response.status).toBe(200);
    });
  });
});
