#!/usr/bin/env python3
"""
Geolocation utilities for reverse geocoding and city lookups.
"""

import requests
from typing import Optional, Tuple
from logger import get_app_logger

app_logger = get_app_logger()

# Simple city name cache to avoid repeated API calls
_city_cache = {}


def reverse_geocode_city(latitude: float, longitude: float) -> Optional[str]:
    """
    Reverse geocode coordinates to get city name using Nominatim (OpenStreetMap).

    Args:
        latitude: Latitude coordinate
        longitude: Longitude coordinate

    Returns:
        City name or None if not found
    """
    # Check cache first
    cache_key = f"{latitude},{longitude}"
    if cache_key in _city_cache:
        return _city_cache[cache_key]

    try:
        # Use Nominatim reverse geocoding API (free, no API key required)
        url = "https://nominatim.openstreetmap.org/reverse"
        params = {
            "lat": latitude,
            "lon": longitude,
            "format": "json",
            "zoom": 10,  # City level
            "addressdetails": 1,
        }
        headers = {"User-Agent": "Krawl-Honeypot/1.0"}  # Required by Nominatim ToS

        response = requests.get(url, params=params, headers=headers, timeout=5)
        response.raise_for_status()

        data = response.json()
        address = data.get("address", {})

        # Try to get city from various possible fields
        city = (
            address.get("city")
            or address.get("town")
            or address.get("village")
            or address.get("municipality")
            or address.get("county")
        )

        # Cache the result
        _city_cache[cache_key] = city

        if city:
            app_logger.debug(f"Reverse geocoded {latitude},{longitude} to {city}")

        return city

    except requests.RequestException as e:
        app_logger.warning(f"Reverse geocoding failed for {latitude},{longitude}: {e}")
        return None
    except Exception as e:
        app_logger.error(f"Error in reverse geocoding: {e}")
        return None


def get_most_recent_geoip_data(results: list) -> Optional[dict]:
    """
    Extract the most recent geoip_data from API results.
    Results are assumed to be sorted by record_added (most recent first).

    Args:
        results: List of result dictionaries from IP reputation API

    Returns:
        Most recent geoip_data dict or None
    """
    if not results:
        return None

    # The first result is the most recent (sorted by record_added)
    most_recent = results[0]
    return most_recent.get("geoip_data")


def extract_city_from_coordinates(geoip_data: dict) -> Optional[str]:
    """
    Extract city name from geoip_data using reverse geocoding.

    Args:
        geoip_data: Dictionary containing location_latitude and location_longitude

    Returns:
        City name or None
    """
    if not geoip_data:
        return None

    latitude = geoip_data.get("location_latitude")
    longitude = geoip_data.get("location_longitude")

    if latitude is None or longitude is None:
        return None

    return reverse_geocode_city(latitude, longitude)
