/**
 * Integration Tests for IP Tracking on Login
 *
 * Tests that IP addresses and geolocation data are correctly
 * captured and stored when users log in via various methods
 */

import { prisma } from "@/lib/db";
import { getLocationFromIP } from "@/lib/geolocation";
import bcrypt from "bcryptjs";

// Mock geolocation to avoid external API calls in tests
jest.mock("@/lib/geolocation", () => ({
  getLocationFromIP: jest.fn(),
  getIPFromRequest: jest.fn(),
}));

// Requires live database - skip in unit test environment
describe.skip("IP Tracking on Login Integration", () => {
  let testUser: any;

  beforeAll(async () => {
    // Create test user
    testUser = await prisma.users.create({
      data: {
        email: "ip-tracking-test@example.com",
        name: "IP Tracking Test User",
        password: await bcrypt.hash("TestPassword123!", 12),
        role: "CUSTOMER",
        isActive: true,
      },
    });
  });

  afterAll(async () => {
    // Cleanup
    await prisma.login_history.deleteMany({
      where: { userId: testUser.id },
    });

    await prisma.users.delete({
      where: { id: testUser.id },
    });
  });

  beforeEach(() => {
    // Mock geolocation response
    (getLocationFromIP as jest.Mock).mockResolvedValue({
      country: "Qatar",
      countryCode: "QA",
      region: "Doha",
      city: "Doha",
      latitude: 25.2854,
      longitude: 51.531,
      timezone: "Asia/Qatar",
    });
  });

  test("should create login history on successful login", async () => {
    const beforeCount = await prisma.login_history.count({
      where: { userId: testUser.id },
    });

    // Simulate creating login history (what auth.ts does)
    const ipAddress = "203.0.113.50";
    const location = await getLocationFromIP(ipAddress);

    await prisma.login_history.create({
      data: {
        userId: testUser.id,
        ipAddress,
        userAgent: "Mozilla/5.0 Test",
        country: location?.country || null,
        countryCode: location?.countryCode || null,
        city: location?.city || null,
        region: location?.region || null,
        latitude: location?.latitude || null,
        longitude: location?.longitude || null,
        timezone: location?.timezone || null,
        provider: "credentials",
        success: true,
      },
    });

    // Update user login info
    await prisma.users.update({
      where: { id: testUser.id },
      data: {
        lastLoginAt: new Date(),
        lastLoginIp: ipAddress,
        lastLoginCountry: location?.country || null,
        lastLoginCity: location?.city || null,
        loginCount: { increment: 1 },
      },
    });

    const afterCount = await prisma.login_history.count({
      where: { userId: testUser.id },
    });

    expect(afterCount).toBe(beforeCount + 1);

    // Verify login history record
    const loginRecord = await prisma.login_history.findFirst({
      where: {
        userId: testUser.id,
        ipAddress,
      },
      orderBy: { createdAt: "desc" },
    });

    expect(loginRecord).toBeDefined();
    expect(loginRecord?.country).toBe("Qatar");
    expect(loginRecord?.city).toBe("Doha");
    expect(loginRecord?.success).toBe(true);

    // Verify user record updated
    const updatedUser = await prisma.users.findUnique({
      where: { id: testUser.id },
      select: {
        lastLoginIp: true,
        lastLoginCountry: true,
        lastLoginCity: true,
        loginCount: true,
      },
    });

    expect(updatedUser?.lastLoginIp).toBe(ipAddress);
    expect(updatedUser?.lastLoginCountry).toBe("Qatar");
    expect(updatedUser?.lastLoginCity).toBe("Doha");
    expect(updatedUser?.loginCount).toBeGreaterThan(0);
  });

  test("should track failed login attempts", async () => {
    const ipAddress = "203.0.113.51";

    await prisma.login_history.create({
      data: {
        userId: testUser.id,
        ipAddress,
        userAgent: "Mozilla/5.0 Test",
        provider: "credentials",
        success: false,
        failReason: "Invalid password",
      },
    });

    const failedLogin = await prisma.login_history.findFirst({
      where: {
        userId: testUser.id,
        success: false,
      },
    });

    expect(failedLogin).toBeDefined();
    expect(failedLogin?.failReason).toBe("Invalid password");
  });

  test("should track logins from different IPs", async () => {
    const ips = ["203.0.113.60", "203.0.113.61", "203.0.113.62"];

    for (const ip of ips) {
      await prisma.login_history.create({
        data: {
          userId: testUser.id,
          ipAddress: ip,
          provider: "credentials",
          success: true,
        },
      });
    }

    const uniqueIPs = await prisma.login_history.findMany({
      where: { userId: testUser.id },
      select: { ipAddress: true },
      distinct: ["ipAddress"],
    });

    expect(uniqueIPs.length).toBeGreaterThanOrEqual(3);
  });

  test("should track logins from different countries", async () => {
    // Mock different locations
    const locations = [
      { country: "Qatar", city: "Doha", ip: "203.0.113.70" },
      { country: "UAE", city: "Dubai", ip: "203.0.113.71" },
      { country: "Saudi Arabia", city: "Riyadh", ip: "203.0.113.72" },
    ];

    for (const loc of locations) {
      await prisma.login_history.create({
        data: {
          userId: testUser.id,
          ipAddress: loc.ip,
          country: loc.country,
          city: loc.city,
          provider: "credentials",
          success: true,
        },
      });
    }

    const uniqueCountries = await prisma.login_history.findMany({
      where: { userId: testUser.id },
      select: { country: true },
      distinct: ["country"],
    });

    expect(uniqueCountries.length).toBeGreaterThanOrEqual(3);
  });

  test("should block login for suspended users", async () => {
    // Suspend user
    await prisma.users.update({
      where: { id: testUser.id },
      data: {
        isSuspended: true,
        isActive: false,
        suspendedReason: "Test suspension",
      },
    });

    // Verify user is suspended
    const user = await prisma.users.findUnique({
      where: { id: testUser.id },
      select: { isSuspended: true, isActive: true },
    });

    expect(user?.isSuspended).toBe(true);
    expect(user?.isActive).toBe(false);

    // Create failed login history for suspended account
    await prisma.login_history.create({
      data: {
        userId: testUser.id,
        ipAddress: "203.0.113.80",
        provider: "credentials",
        success: false,
        failReason: "Account suspended",
      },
    });

    const blockedLogin = await prisma.login_history.findFirst({
      where: {
        userId: testUser.id,
        failReason: "Account suspended",
      },
    });

    expect(blockedLogin).toBeDefined();
    expect(blockedLogin?.success).toBe(false);

    // Cleanup: reactivate user
    await prisma.users.update({
      where: { id: testUser.id },
      data: {
        isSuspended: false,
        isActive: true,
        suspendedReason: null,
      },
    });
  });

  test("should track different login providers (credentials, google)", async () => {
    // Credentials login
    await prisma.login_history.create({
      data: {
        userId: testUser.id,
        ipAddress: "203.0.113.90",
        provider: "credentials",
        success: true,
      },
    });

    // Google login
    await prisma.login_history.create({
      data: {
        userId: testUser.id,
        ipAddress: "203.0.113.91",
        provider: "google",
        success: true,
      },
    });

    const credentialsLogins = await prisma.login_history.count({
      where: {
        userId: testUser.id,
        provider: "credentials",
      },
    });

    const googleLogins = await prisma.login_history.count({
      where: {
        userId: testUser.id,
        provider: "google",
      },
    });

    expect(credentialsLogins).toBeGreaterThan(0);
    expect(googleLogins).toBeGreaterThan(0);
  });

  test("should handle private IP addresses gracefully", async () => {
    (getLocationFromIP as jest.Mock).mockResolvedValue({
      country: "Local Development",
      countryCode: "XX",
      region: "N/A",
      city: "localhost",
      latitude: 0,
      longitude: 0,
      timezone: "UTC",
    });

    const privateIP = "192.168.1.100";
    const location = await getLocationFromIP(privateIP);

    await prisma.login_history.create({
      data: {
        userId: testUser.id,
        ipAddress: privateIP,
        country: location?.country || null,
        city: location?.city || null,
        provider: "credentials",
        success: true,
      },
    });

    const loginRecord = await prisma.login_history.findFirst({
      where: {
        userId: testUser.id,
        ipAddress: privateIP,
      },
    });

    expect(loginRecord).toBeDefined();
    expect(loginRecord?.country).toBe("Local Development");
  });

  test("should calculate unique IPs correctly", async () => {
    // Get all login history for user
    const loginHistory = await prisma.login_history.findMany({
      where: { userId: testUser.id },
      select: { ipAddress: true },
    });

    const uniqueIPs = new Set(loginHistory.map((l) => l.ipAddress));

    expect(uniqueIPs.size).toBeGreaterThan(0);
    expect(uniqueIPs.size).toBeLessThanOrEqual(loginHistory.length);
  });

  test("should calculate success rate correctly", async () => {
    const loginHistory = await prisma.login_history.findMany({
      where: { userId: testUser.id },
      select: { success: true },
    });

    const successful = loginHistory.filter((l) => l.success).length;
    const total = loginHistory.length;
    const successRate = total > 0 ? (successful / total) * 100 : 0;

    expect(successRate).toBeGreaterThanOrEqual(0);
    expect(successRate).toBeLessThanOrEqual(100);
  });
});
