import type { LocationData } from "./deviceFingerprinting.ts";

/**
 * IP Geolocation Service
 * Tracks IP addresses and detects VPN/Proxy usage
 */

// Mock geolocation data - in production, use MaxMind GeoIP2 or similar
const MOCK_GEOLOCATION_DB: Record<string, LocationData> = {
  "127.0.0.1": {
    country: "US",
    city: "Local",
    latitude: 37.7749,
    longitude: -122.4194,
    timezone: "America/Los_Angeles",
    isp: "Local",
    isVPN: false,
    isProxy: false,
  },
  "0.0.0.0": {
    country: "Unknown",
    city: "Unknown",
    latitude: 0,
    longitude: 0,
    timezone: "UTC",
    isp: "Unknown",
    isVPN: false,
    isProxy: false,
  },
};

// Known VPN/Proxy IP ranges (simplified - in production use comprehensive database)
const VPN_PROXY_INDICATORS = {
  vpnProviders: [
    "expressvpn",
    "nordvpn",
    "surfshark",
    "protonvpn",
    "cyberghost",
    "privateinternet",
    "windscribe",
    "hotspotshield",
  ],
  proxyServices: ["proxy", "anonymizer", "vpn", "tor", "relay"],
};

/**
 * Get geolocation data for IP address
 */
export async function getIPGeolocation(ipAddress: string): Promise<LocationData> {
  // Check mock database first
  if (MOCK_GEOLOCATION_DB[ipAddress]) {
    return MOCK_GEOLOCATION_DB[ipAddress];
  }

  try {
    // In production, integrate with MaxMind GeoIP2 or similar
    // const response = await fetch(`https://geoip.maxmind.com/geoip/v2.1/city/${ipAddress}`, {
    //   headers: { Authorization: `Bearer ${process.env.MAXMIND_API_KEY}` }
    // });

    // For now, return default location
    return {
      country: "Unknown",
      city: "Unknown",
      latitude: 0,
      longitude: 0,
      timezone: "UTC",
      isp: "Unknown",
      isVPN: false,
      isProxy: false,
    };
  } catch (error) {
    console.error("[IP Geolocation] Failed to get geolocation:", error);
    return {
      country: "Unknown",
      city: "Unknown",
      latitude: 0,
      longitude: 0,
      timezone: "UTC",
      isp: "Unknown",
      isVPN: false,
      isProxy: false,
    };
  }
}

/**
 * Detect if IP is from VPN or Proxy service
 */
export function isVPNOrProxy(ipAddress: string, isp: string, userAgent: string): boolean {
  // Check ISP name for VPN/Proxy indicators
  const lowerISP = isp.toLowerCase();
  for (const provider of VPN_PROXY_INDICATORS.vpnProviders) {
    if (lowerISP.includes(provider)) {
      return true;
    }
  }

  for (const service of VPN_PROXY_INDICATORS.proxyServices) {
    if (lowerISP.includes(service)) {
      return true;
    }
  }

  // Check for common VPN/Proxy user agent patterns
  const lowerUA = userAgent.toLowerCase();
  const vpnPatterns = [
    "vpn",
    "proxy",
    "tor",
    "anonymizer",
    "hide",
    "private",
    "secure",
  ];

  for (const pattern of vpnPatterns) {
    if (lowerUA.includes(pattern)) {
      return true;
    }
  }

  return false;
}

/**
 * Get timezone from geolocation
 */
export function getTimezoneFromLocation(country: string, city: string): string {
  // Simplified timezone mapping - in production use comprehensive database
  const timezoneMap: Record<string, string> = {
    US: "America/New_York",
    GB: "Europe/London",
    DE: "Europe/Berlin",
    FR: "Europe/Paris",
    JP: "Asia/Tokyo",
    CN: "Asia/Shanghai",
    IN: "Asia/Kolkata",
    AU: "Australia/Sydney",
    CA: "America/Toronto",
    BR: "America/Sao_Paulo",
  };

  return timezoneMap[country] || "UTC";
}

/**
 * Validate IP address format
 */
export function isValidIPAddress(ip: string): boolean {
  // IPv4 validation
  const ipv4Regex =
    /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;

  // IPv6 validation (simplified)
  const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::1)$/;

  return ipv4Regex.test(ip) || ipv6Regex.test(ip) || ip === "127.0.0.1";
}

/**
 * Extract IP from request headers
 */
export function extractIPFromRequest(
  headers: Record<string, string | string[] | undefined>
): string {
  // Check common proxy headers first
  const forwardedFor = headers["x-forwarded-for"];
  if (forwardedFor) {
    const ips = Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor;
    return ips.split(",")[0].trim();
  }

  const realIP = headers["x-real-ip"];
  if (realIP) {
    return Array.isArray(realIP) ? realIP[0] : realIP;
  }

  const clientIP = headers["x-client-ip"];
  if (clientIP) {
    return Array.isArray(clientIP) ? clientIP[0] : clientIP;
  }

  // Fallback to connection IP
  const remoteAddr = headers["x-forwarded-for"] || headers["remote-addr"];
  if (remoteAddr) {
    return Array.isArray(remoteAddr) ? remoteAddr[0] : remoteAddr;
  }

  return "0.0.0.0";
}

/**
 * Get location risk score
 */
export function getLocationRiskScore(location: LocationData): number {
  let riskScore = 0;

  // VPN/Proxy usage increases risk
  if (location.isVPN || location.isProxy) {
    riskScore += 20;
  }

  // Certain countries have higher risk (simplified - customize based on business rules)
  const highRiskCountries = ["KP", "IR", "SY", "CU"]; // North Korea, Iran, Syria, Cuba
  if (highRiskCountries.includes(location.country)) {
    riskScore += 30;
  }

  // Unknown location increases risk
  if (location.country === "Unknown") {
    riskScore += 15;
  }

  return Math.min(riskScore, 100);
}

/**
 * Format location for display
 */
export function formatLocation(location: LocationData): string {
  if (location.city && location.country) {
    return `${location.city}, ${location.country}`;
  }
  return location.country || "Unknown";
}

/**
 * Batch geolocation lookup
 */
export async function batchGetIPGeolocation(ips: string[]): Promise<Map<string, LocationData>> {
  const results = new Map<string, LocationData>();

  for (const ip of ips) {
    const location = await getIPGeolocation(ip);
    results.set(ip, location);
  }

  return results;
}

/**
 * Get IP reputation score
 */
export async function getIPReputation(ipAddress: string): Promise<number> {
  // In production, integrate with IP reputation services like AbuseIPDB
  // For now, return base score
  let score = 0;

  // Check if IP is in known blacklist
  const blacklistedIPs = [
    "192.0.2.1", // TEST-NET-1
    "198.51.100.1", // TEST-NET-2
    "203.0.113.1", // TEST-NET-3
  ];

  if (blacklistedIPs.includes(ipAddress)) {
    score += 50;
  }

  // Check if IP is private
  const privateRanges = [
    /^10\./,
    /^172\.(1[6-9]|2[0-9]|3[01])\./,
    /^192\.168\./,
    /^127\./,
  ];

  for (const range of privateRanges) {
    if (range.test(ipAddress)) {
      score -= 10; // Private IPs are generally safe
      break;
    }
  }

  return Math.max(0, Math.min(score, 100));
}
