type IpGeoInfo = {
  ip: string;
  city: string;
  country: string;
  countryCode: string;
  lat: number | null;
  lon: number | null;
};

const cache = new Map<string, { data: IpGeoInfo; expiresAt: number }>();
const CACHE_TTL_MS = 60 * 60 * 1000;

function getCached(ip: string): IpGeoInfo | undefined {
  const entry = cache.get(ip);
  if (!entry) return undefined;
  if (Date.now() > entry.expiresAt) {
    cache.delete(ip);
    return undefined;
  }
  return entry.data;
}

function setCache(ip: string, info: IpGeoInfo): void {
  cache.set(ip, { data: info, expiresAt: Date.now() + CACHE_TTL_MS });
}

async function fetchGeoInfo(ip: string): Promise<IpGeoInfo | null> {
  if (ip === '127.0.0.1' || ip === '::1' || ip.startsWith('192.168.') || ip.startsWith('10.')) {
    return {
      ip,
      city: 'Red local',
      country: 'Red local',
      countryCode: 'LOCAL',
      lat: null,
      lon: null,
    };
  }

  const cached = getCached(ip);
  if (cached) return cached;

  try {
    const response = await fetch(
      `http://ip-api.com/json/${ip}?fields=status,country,countryCode,city,lat,lon,query`
    );
    if (!response.ok) return null;

    const data = await response.json();
    if (data.status !== 'success') return null;

    const info: IpGeoInfo = {
      ip: data.query,
      city: data.city || 'Desconocida',
      country: data.country || 'Desconocido',
      countryCode: data.countryCode || '',
      lat: data.lat ?? null,
      lon: data.lon ?? null,
    };

    setCache(ip, info);
    return info;
  } catch {
    return null;
  }
}

export type { IpGeoInfo };
export { fetchGeoInfo };
