# -*- coding: utf-8 -*-
"""
geo.py - Wandelt einen Geburtsort (Klartext) in Koordinaten + Zeitzone um.

WICHTIG zur Zeitzone:
  Diese Funktion liefert nur den Zeitzonen-NAMEN (z.B. 'Europe/Berlin').
  Die eigentliche Umrechnung Lokalzeit -> Weltzeit (UT) macht weiterhin
  local_to_ut() in radix_engine.py - dort ist die korrekte historische
  Logik hinterlegt (Deutschland: Sommerzeit erst ab 1980 usw.).
  geo.py rechnet KEINE Zeiten um.
"""
import time
from geopy.geocoders import Nominatim
from timezonefinder import TimezoneFinder

_tf = TimezoneFinder()
# Nominatim verlangt einen aussagekraeftigen User-Agent (eigene Domain/Kontakt).
_geocoder = Nominatim(user_agent="fine-senses-hd-analyse/1.0 (service@fine-senses.de)")


class GeocodingError(Exception):
    """Wird geworfen, wenn der Ort nicht eindeutig aufgeloest werden kann."""
    pass


def tz_from_coords(lat, lon):
    """
    Bestimmt nur die Zeitzone aus bereits bekannten Koordinaten.
    Genutzt, wenn der Checkout die Koordinaten schon mitliefert
    (Ortsauswahl per Autovervollstaendigung) - dann ist KEIN Geocoding noetig.
    """
    lat = float(lat)
    lon = float(lon)
    tz = _tf.timezone_at(lat=lat, lng=lon)
    if tz is None:
        tz = _tf.closest_timezone_at(lat=lat, lng=lon)
    if tz is None:
        raise GeocodingError(f"Keine Zeitzone fuer Koordinaten {lat},{lon} ermittelbar.")
    return {"lat": round(lat, 4), "lon": round(lon, 4), "tz": tz}


def resolve_birthplace(ortsname, land=None, plz=None, retries=2):
    """
    Loest einen Geburtsort auf (Fallback, wenn keine Koordinaten aus dem
    Checkout mitkamen). Land und PLZ praezisieren die Suche, falls vorhanden.
    Rueckgabe: dict(lat, lon, tz, display_name)
    Wirft GeocodingError, wenn nichts gefunden wird.
    """
    if not ortsname or not ortsname.strip():
        raise GeocodingError("Kein Geburtsort angegeben.")

    # Suchstring praezisieren: "Hamburg, 20095, Deutschland"
    teile = [ortsname.strip()]
    if plz and str(plz).strip():
        teile.append(str(plz).strip())
    if land and str(land).strip():
        teile.append(str(land).strip())
    ort = ", ".join(teile)
    last_err = None
    for versuch in range(retries + 1):
        try:
            loc = _geocoder.geocode(ort, language="de", timeout=10)
            if loc is None:
                raise GeocodingError(f"Ort nicht gefunden: {ort!r}")
            lat, lon = float(loc.latitude), float(loc.longitude)
            tz = _tf.timezone_at(lat=lat, lng=lon)
            if tz is None:
                # Fallback: timezone_at kann an Kuesten/Sonderfaellen None geben
                tz = _tf.closest_timezone_at(lat=lat, lng=lon)
            if tz is None:
                raise GeocodingError(f"Keine Zeitzone fuer {ort!r} ermittelbar.")
            return {
                "lat": round(lat, 4),
                "lon": round(lon, 4),
                "tz": tz,
                "display_name": loc.address,
            }
        except GeocodingError:
            raise
        except Exception as e:  # Netzwerk / Rate-Limit -> kurz warten, neu versuchen
            last_err = e
            time.sleep(1.5 * (versuch + 1))
    raise GeocodingError(f"Geocoding fehlgeschlagen fuer {ort!r}: {last_err}")


if __name__ == '__main__':
    # Schnelltest
    for ort in ['Hamburg', 'Karlsruhe', 'Wien, Oesterreich']:
        try:
            print(ort, '->', resolve_birthplace(ort))
        except GeocodingError as e:
            print(ort, '-> FEHLER:', e)
        time.sleep(1)
