/**
 * Geolocation Helper for IP Address Tracking
 *
 * Provides IP-based geolocation using geoip-lite (offline, fast)
 * with fallback to ipapi.co (online, more detailed) for production
 */

let geoip: any = null;
try {
  geoip = require('geoip-lite');
} catch (error) {
  console.warn('geoip-lite not available, using API fallback only');
}

// ============================================
// TYPES
// ============================================

export interface GeoLocation {
  country: string;
  countryCode: string;
  region: string;
  city: string;
  latitude: number;
  longitude: number;
  timezone: string;
}

// ============================================
// MAIN GEOLOCATION FUNCTION
// ============================================

export async function getLocationFromIP(ip: string): Promise<GeoLocation | null> {
  try {
    // ============================================
    // FILTER OUT PRIVATE IPS
    // ============================================
    if (isPrivateIP(ip)) {
      console.log(`⚠️ Private IP detected: ${ip}, using fallback`);
      return getDefaultLocation();
    }

    // ============================================
    // METHOD 1: GEOIP-LITE (FREE, OFFLINE, FAST)
    // ============================================
    if (geoip) {
      try {
        const geo = geoip.lookup(ip);

        if (geo) {
          return {
            country: getCountryName(geo.country),
            countryCode: geo.country,
            region: geo.region,
            city: '', // geoip-lite doesn't provide city
            latitude: geo.ll[0],
            longitude: geo.ll[1],
            timezone: geo.timezone,
          };
        }
      } catch (geoipError) {
        console.warn('geoip-lite lookup failed, using API fallback');
      }
    }

    // ============================================
    // METHOD 2: IPAPI.CO (FREE API, MORE DETAILED)
    // Fallback when geoip-lite doesn't have data
    // ============================================
    try {
      const response = await fetch(`https://ipapi.co/${ip}/json/`, {
        headers: { 'User-Agent': 'Mawidi-GeoIP/1.0' },
        signal: AbortSignal.timeout(2000), // 2 second timeout (reduced from 5s for performance)
      });

      if (!response.ok) {
        throw new Error(`GeoIP API error: ${response.status}`);
      }

      const data = await response.json();

      if (data.error) {
        console.error('GeoIP API error:', data.reason);
        return null;
      }

      return {
        country: data.country_name,
        countryCode: data.country_code,
        region: data.region,
        city: data.city,
        latitude: data.latitude,
        longitude: data.longitude,
        timezone: data.timezone,
      };
    } catch (apiError) {
      console.error('❌ ipapi.co fetch error:', apiError);
      return null;
    }

  } catch (error) {
    console.error('❌ Geolocation error:', error);
    return null;
  }
}

// ============================================
// HELPER: EXTRACT IP FROM REQUEST
// ============================================

export function getIPFromRequest(request: Request): string {
  // Check various headers in order of preference
  const forwarded = request.headers.get('x-forwarded-for');
  const realIp = request.headers.get('x-real-ip');
  const cfConnectingIp = request.headers.get('cf-connecting-ip'); // Cloudflare
  const vercelIp = request.headers.get('x-vercel-forwarded-for'); // Vercel

  // x-forwarded-for can be a comma-separated list
  if (forwarded) {
    return forwarded.split(',')[0].trim();
  }

  return realIp || cfConnectingIp || vercelIp || '127.0.0.1';
}

// ============================================
// HELPER: CHECK IF PRIVATE IP
// ============================================

function isPrivateIP(ip: string): boolean {
  // Localhost
  if (ip === '127.0.0.1' || ip === '::1') return true;

  // Private networks (RFC 1918)
  if (ip.startsWith('192.168.')) return true;
  if (ip.startsWith('10.')) return true;
  if (/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(ip)) return true;

  // Link-local
  if (ip.startsWith('169.254.')) return true;

  return false;
}

// ============================================
// HELPER: DEFAULT LOCATION FOR PRIVATE IPS
// ============================================

function getDefaultLocation(): GeoLocation {
  return {
    country: 'Local Development',
    countryCode: 'XX',
    region: 'N/A',
    city: 'localhost',
    latitude: 0,
    longitude: 0,
    timezone: 'UTC',
  };
}

// ============================================
// HELPER: COUNTRY CODE TO NAME
// ============================================

function getCountryName(code: string): string {
  const countries: { [key: string]: string } = {
    'AE': 'United Arab Emirates',
    'SA': 'Saudi Arabia',
    'QA': 'Qatar',
    'KW': 'Kuwait',
    'BH': 'Bahrain',
    'OM': 'Oman',
    'US': 'United States',
    'GB': 'United Kingdom',
    'IN': 'India',
    'PK': 'Pakistan',
    'EG': 'Egypt',
    'JO': 'Jordan',
    'LB': 'Lebanon',
    'IQ': 'Iraq',
    'SY': 'Syria',
    'YE': 'Yemen',
    'MA': 'Morocco',
    'TN': 'Tunisia',
    'DZ': 'Algeria',
    'LY': 'Libya',
    'SD': 'Sudan',
    'TR': 'Turkey',
    'IR': 'Iran',
    'IL': 'Israel',
    'PS': 'Palestine',
    'AF': 'Afghanistan',
    'BD': 'Bangladesh',
    'MY': 'Malaysia',
    'ID': 'Indonesia',
    'SG': 'Singapore',
    'TH': 'Thailand',
    'PH': 'Philippines',
    'VN': 'Vietnam',
    'CN': 'China',
    'JP': 'Japan',
    'KR': 'South Korea',
    'AU': 'Australia',
    'NZ': 'New Zealand',
    'CA': 'Canada',
    'MX': 'Mexico',
    'BR': 'Brazil',
    'AR': 'Argentina',
    'CL': 'Chile',
    'CO': 'Colombia',
    'FR': 'France',
    'DE': 'Germany',
    'IT': 'Italy',
    'ES': 'Spain',
    'PT': 'Portugal',
    'NL': 'Netherlands',
    'BE': 'Belgium',
    'CH': 'Switzerland',
    'AT': 'Austria',
    'SE': 'Sweden',
    'NO': 'Norway',
    'DK': 'Denmark',
    'FI': 'Finland',
    'PL': 'Poland',
    'RU': 'Russia',
    'UA': 'Ukraine',
    'RO': 'Romania',
    'GR': 'Greece',
    'CZ': 'Czech Republic',
    'HU': 'Hungary',
    'ZA': 'South Africa',
    'NG': 'Nigeria',
    'KE': 'Kenya',
    'ET': 'Ethiopia',
    'GH': 'Ghana',
  };

  return countries[code] || code;
}

// ============================================
// BATCH LOOKUP FOR PERFORMANCE
// ============================================

export async function batchGeoLookup(ips: string[]): Promise<Map<string, GeoLocation | null>> {
  const results = new Map<string, GeoLocation | null>();

  // Process in parallel with rate limiting
  const chunks = chunkArray(ips, 10); // 10 at a time

  for (const chunk of chunks) {
    const promises = chunk.map(async ip => {
      const location = await getLocationFromIP(ip);
      results.set(ip, location);
    });

    await Promise.all(promises);

    // Rate limiting: wait 100ms between batches
    if (chunks.indexOf(chunk) < chunks.length - 1) {
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }

  return results;
}

function chunkArray<T>(array: T[], size: number): T[][] {
  const chunks: T[][] = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
}
