import { Reader } from '@maxmind/geoip2-node';
import fs from 'fs';
import { env } from '../config/env';
import { logger } from '../utils/logger';

export interface GeoResult {
  country: string | null;   // ISO 3166-1 alpha-2
  region: string | null;
  city: string | null;
  latitude: number | null;
  longitude: number | null;
}

class GeoIPService {
  private reader: Reader | null = null;
  private loadAttempted = false;

  private async ensureReader(): Promise<Reader | null> {
    if (this.reader) return this.reader;
    if (this.loadAttempted) return null;

    this.loadAttempted = true;
    const dbPath = env.GEOIP_DB_PATH;

    if (!fs.existsSync(dbPath)) {
      logger.info('GeoIP database not found — geo lookups disabled');
      return null;
    }

    try {
      this.reader = await Reader.open(dbPath);
      logger.info('GeoIP database loaded successfully');
      return this.reader;
    } catch (err) {
      logger.warn('Failed to load GeoIP database', { error: (err as Error).message });
      return null;
    }
  }

  async lookup(ip: string): Promise<GeoResult | null> {
    if (!ip) return null;

    const reader = await this.ensureReader();
    if (!reader) return null;

    try {
      const response = (reader as any).city(ip);
      return {
        country: response?.country?.isoCode ?? null,
        region: response?.subdivisions?.[0]?.names?.en ?? null,
        city: response?.city?.names?.en ?? null,
        latitude: response?.location?.latitude ?? null,
        longitude: response?.location?.longitude ?? null,
      };
    } catch {
      // Private IPs, invalid addresses, or not-found entries
      return null;
    }
  }

  /** Force-reload the database (e.g., after a fresh download) */
  async reload(): Promise<void> {
    this.reader = null;
    this.loadAttempted = false;
    await this.ensureReader();
  }
}

export const geoipService = new GeoIPService();
