/**
 * Unit tests for WhatsApp extended routes:
 * - /api/whatsapp/feature-access (GET)
 * - /api/whatsapp/language-preference (GET, POST)
 * - /api/whatsapp/user-info (GET)
 */

// 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/system-settings.service", () => ({
  systemSettingsService: {
    validateN8NToken: jest.fn(),
  },
}));

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

jest.mock("@/lib/validators/whatsapp-ai.validator", () => ({
  FeatureAccessQuerySchema: {
    safeParse: jest.fn(),
  },
  LanguagePreferenceGetSchema: {
    safeParse: jest.fn(),
  },
  LanguagePreferenceSetSchema: {
    safeParse: jest.fn(),
  },
  OrganizationIdSchema: {
    safeParse: jest.fn(),
  },
  PhoneNumberSchema: {
    safeParse: jest.fn(),
  },
}));

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

jest.mock("next/server", () => {
  const NextResponseMock = function (body: any, init?: any) {
    return {
      status: init?.status || 200,
      headers: new Map(Object.entries(init?.headers || {})),
      json: async () => (body ? JSON.parse(body) : null),
      body,
    };
  };
  NextResponseMock.json = jest.fn((data: any, options?: any) => ({
    status: options?.status || 200,
    headers: new Map(Object.entries(options?.headers || {})),
    json: async () => data,
  }));
  return {
    NextRequest: jest.fn(),
    NextResponse: NextResponseMock,
  };
});

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { systemSettingsService } from "@/lib/services/system-settings.service";
import {
  getFeatureAccess,
  getFeatureUsage,
  isWithinLimits,
} from "@/lib/services/whatsapp-feature-access.service";
import {
  FeatureAccessQuerySchema,
  LanguagePreferenceGetSchema,
  LanguagePreferenceSetSchema,
  OrganizationIdSchema,
  PhoneNumberSchema,
} from "@/lib/validators/whatsapp-ai.validator";
import {
  getLanguagePreference,
  setLanguagePreference,
} from "@/lib/services/whatsapp-language.service";

// ─── Feature Access ──────────────────────────────────────────────────────

// Route not yet implemented
describe.skip("GET /api/whatsapp/feature-access", () => {
  let featureModule: any;

  beforeAll(async () => {
    featureModule = await import("@/app/api/whatsapp/feature-access/route");
  });

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

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

  it("should return 401 without auth", async () => {
    const response = await featureModule.GET(mockRequest());
    const body = await response.json();
    expect(response.status).toBe(401);
  });

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

    const response = await featureModule.GET(mockRequest("Bearer bad-token"));
    const body = await response.json();
    expect(response.status).toBe(401);
  });

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

    const response = await featureModule.GET(mockRequest("Bearer valid-token"));
    const body = await response.json();
    expect(response.status).toBe(400);
  });

  it("should return feature access successfully", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (FeatureAccessQuerySchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: { organizationId: "org-1", features: ["payments"] },
    });
    (getFeatureAccess as jest.Mock).mockResolvedValue({
      tier: "professional",
      tierLevel: 2,
      features: { payments: true },
      limits: {},
    });
    (getFeatureUsage as jest.Mock).mockResolvedValue({ messagesUsed: 50 });
    (isWithinLimits as jest.Mock).mockResolvedValue({
      withinLimits: true,
      violations: [],
    });

    const response = await featureModule.GET(
      mockRequest("Bearer valid-token", {
        organizationId: "org-1",
        features: "payments",
      }),
    );
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(body.data.tier).toBe("professional");
    expect(body.data.withinLimits).toBe(true);
  });

  it("should return 500 on error", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (FeatureAccessQuerySchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: { organizationId: "org-1" },
    });
    (getFeatureAccess as jest.Mock).mockRejectedValue(
      new Error("Service error"),
    );

    const response = await featureModule.GET(mockRequest("Bearer valid-token"));
    const body = await response.json();
    expect(response.status).toBe(500);
  });
});

// ─── Language Preference ─────────────────────────────────────────────────

// Route not yet implemented
describe.skip("GET /api/whatsapp/language-preference", () => {
  let langModule: any;

  beforeAll(async () => {
    langModule = await import("@/app/api/whatsapp/language-preference/route");
  });

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

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

  it("should return 401 without auth", async () => {
    const response = await langModule.GET(mockRequest());
    const body = await response.json();
    expect(response.status).toBe(401);
  });

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

    const response = await langModule.GET(mockRequest("Bearer valid-token"));
    const body = await response.json();
    expect(response.status).toBe(400);
  });

  it("should return null language when no preference set", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (LanguagePreferenceGetSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: { organizationId: "org-1", phone: "+97412345678" },
    });
    (getLanguagePreference as jest.Mock).mockResolvedValue(null);

    const response = await langModule.GET(mockRequest("Bearer valid-token"));
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(body.data.language).toBeNull();
  });

  it("should return language preference", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (LanguagePreferenceGetSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: { organizationId: "org-1", phone: "+97412345678" },
    });
    (getLanguagePreference as jest.Mock).mockResolvedValue("ar");

    const response = await langModule.GET(mockRequest("Bearer valid-token"));
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(body.data.language).toBe("ar");
  });
});

// Route not yet implemented
describe.skip("POST /api/whatsapp/language-preference", () => {
  let langModule: any;

  beforeAll(async () => {
    langModule = await import("@/app/api/whatsapp/language-preference/route");
  });

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

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

  it("should return 401 without auth", async () => {
    const response = await langModule.POST(mockRequest());
    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,
    );
    (LanguagePreferenceSetSchema.safeParse as jest.Mock).mockReturnValue({
      success: false,
      error: { errors: [{ message: "Required" }] },
    });

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

  it("should set language preference successfully", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (LanguagePreferenceSetSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: {
        organizationId: "org-1",
        phone: "+97412345678",
        language: "ar",
      },
    });
    (setLanguagePreference as jest.Mock).mockResolvedValue({
      organizationId: "org-1",
      userId: "+97412345678",
      language: "ar",
      selectedAt: new Date("2026-02-17T10:00:00Z"),
    });

    const response = await langModule.POST(
      mockRequest("Bearer valid-token", {
        organizationId: "org-1",
        phone: "+97412345678",
        language: "ar",
      }),
    );
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(body.data.language).toBe("ar");
  });
});

// ─── User Info ───────────────────────────────────────────────────────────

// Route not yet implemented
describe.skip("GET /api/whatsapp/user-info", () => {
  let userInfoModule: any;

  beforeAll(async () => {
    userInfoModule = await import("@/app/api/whatsapp/user-info/route");
  });

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

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

  it("should return 401 without auth", async () => {
    const response = await userInfoModule.GET(mockRequest());
    const body = await response.json();
    expect(response.status).toBe(401);
  });

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

    const response = await userInfoModule.GET(mockRequest("Bearer bad-token"));
    const body = await response.json();
    expect(response.status).toBe(401);
  });

  it("should return 400 for invalid params", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (OrganizationIdSchema.safeParse as jest.Mock).mockReturnValue({
      success: false,
    });
    (PhoneNumberSchema.safeParse as jest.Mock).mockReturnValue({
      success: false,
    });

    const response = await userInfoModule.GET(
      mockRequest("Bearer valid-token"),
    );
    const body = await response.json();
    expect(response.status).toBe(400);
  });

  it("should return 404 for unknown organization", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (OrganizationIdSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: "org-1",
    });
    (PhoneNumberSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: "+97412345678",
    });
    (prisma.organizations.findUnique as jest.Mock).mockResolvedValue(null);

    const response = await userInfoModule.GET(
      mockRequest("Bearer valid-token", {
        organizationId: "org-1",
        phone: "+97412345678",
      }),
    );
    const body = await response.json();
    expect(response.status).toBe(404);
  });

  it("should return user info successfully", async () => {
    (systemSettingsService.validateN8NToken as jest.Mock).mockResolvedValue(
      true,
    );
    (OrganizationIdSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: "org-1",
    });
    (PhoneNumberSchema.safeParse as jest.Mock).mockReturnValue({
      success: true,
      data: "+97412345678",
    });
    (prisma.organizations.findUnique as jest.Mock).mockResolvedValue({
      ownerId: "user-1",
      name: "Test Org",
    });
    (prisma.bookings.findMany as jest.Mock).mockResolvedValue([
      {
        id: "b-1",
        customerName: "Ahmed",
        appointmentDate: new Date("2026-03-01"),
        duration: 30,
        status: "confirmed",
        notes: null,
        createdAt: new Date(),
      },
    ]);
    (prisma.org_whatsapp_conversations.findMany as jest.Mock).mockResolvedValue(
      [
        {
          id: "conv-1",
          language: "ar",
          messageCount: 5,
          lastMessageAt: new Date(),
          createdAt: new Date(),
        },
      ],
    );
    (
      prisma.user_language_preferences.findUnique as jest.Mock
    ).mockResolvedValue({
      language: "ar",
      selectedAt: new Date(),
    });

    const response = await userInfoModule.GET(
      mockRequest("Bearer valid-token", {
        organizationId: "org-1",
        phone: "+97412345678",
      }),
    );
    const body = await response.json();
    expect(body.success).toBe(true);
    expect(body.data.name).toBe("Ahmed");
    expect(body.data.language).toBe("ar");
    expect(body.data.totalBookings).toBe(1);
  });
});
