#!/usr/bin/env python3
"""
Geocodierung von Orten aus KI-Zusammenfassungen.
Nutzt Nominatim (OpenStreetMap) für Hagen-spezifische Orte.
"""

import argparse
import json
import sqlite3
import time
from pathlib import Path

import httpx

PROJECT_ROOT = Path(__file__).resolve().parent.parent
DB_PATH = PROJECT_ROOT / "data" / "tracker_remote.db"

# Nominatim API (OpenStreetMap)
NOMINATIM_URL = "https://nominatim.openstreetmap.org/search"
USER_AGENT = "Antragstracker-Hagen/1.0 (tobias.roedel@econgood.org)"

# Hagen Bounding Box (ungefähr)
HAGEN_BBOX = "7.35,51.30,7.65,51.45"  # minLon,minLat,maxLon,maxLat

# Generische Begriffe die nicht geocodiert werden sollten
BLACKLIST = {
    "polizeiwache", "polizei", "feuerwehr", "krankenhaus", "rathaus",
    "aldi", "aldi-markt", "lidl", "rewe", "edeka", "penny", "netto",
    "schule", "grundschule", "gymnasium", "kindergarten", "kita",
    "spielplatz", "kirche", "friedhof", "sportplatz", "schwimmbad",
    "bushaltestelle", "bahnhof", "parkplatz", "parkhaus",
}


def get_db():
    conn = sqlite3.connect(str(DB_PATH))
    conn.row_factory = sqlite3.Row
    return conn


def geocode_ort(client: httpx.Client, name: str) -> tuple[float, float] | None:
    """Geocodiert einen Ort in Hagen."""
    # Verschiedene Suchvarianten
    queries = [
        f"{name}, Hagen, Germany",
        f"{name}, Hagen",
        f"{name} Hagen",
    ]
    
    for q in queries:
        try:
            resp = client.get(
                NOMINATIM_URL,
                params={
                    "q": q,
                    "format": "json",
                    "limit": 1,
                    "viewbox": HAGEN_BBOX,
                    "bounded": 1,
                },
                headers={"User-Agent": USER_AGENT},
                timeout=10
            )
            resp.raise_for_status()
            
            results = resp.json()
            if results:
                lat = float(results[0]["lat"])
                lon = float(results[0]["lon"])
                return (lat, lon)
            
        except Exception as e:
            print(f"    Geocoding-Fehler für '{q}': {e}")
        
        time.sleep(1.1)  # Nominatim Rate Limit: 1 req/s
    
    return None


def extract_orte_from_ki(conn: sqlite3.Connection) -> list[tuple[int, str, str]]:
    """Extrahiert Orte aus ki_bewertungen.anmerkungen.
    Returns: List of (vorlage_id, ort_name, kontext)
    """
    rows = conn.execute("""
        SELECT vorlage_id, anmerkungen
        FROM ki_bewertungen
        WHERE typ = 'zusammenfassung'
          AND anmerkungen IS NOT NULL
    """).fetchall()
    
    orte = []
    for vorlage_id, anmerkungen in rows:
        try:
            data = json.loads(anmerkungen)
            for ort in data.get("betroffene_orte", []):
                if ort and len(ort) > 2:
                    orte.append((vorlage_id, ort, data.get("kernforderung", "")))
        except:
            continue
    
    return orte


def process_ort(conn: sqlite3.Connection, client: httpx.Client, 
                vorlage_id: int, ort_name: str, kontext: str) -> bool:
    """Verarbeitet einen einzelnen Ort."""
    # Normalisieren
    ort_name_clean = ort_name.strip()
    
    # Blacklist prüfen
    if ort_name_clean.lower() in BLACKLIST:
        print(f"  ⊘ {ort_name_clean} (generisch, übersprungen)")
        return False
    
    # Zu kurze Namen ignorieren
    if len(ort_name_clean) < 4:
        return False
    
    # Prüfen ob Ort schon existiert
    existing = conn.execute(
        "SELECT id, lat, lon FROM orte WHERE name = ?",
        (ort_name_clean,)
    ).fetchone()
    
    if existing:
        ort_id = existing["id"]
        # Verknüpfung erstellen falls nicht vorhanden
        conn.execute("""
            INSERT OR IGNORE INTO vorlagen_orte (vorlage_id, ort_id, kontext)
            VALUES (?, ?, ?)
        """, (vorlage_id, ort_id, kontext[:500] if kontext else None))
        conn.execute("UPDATE orte SET vorlage_count = vorlage_count + 1 WHERE id = ?", (ort_id,))
        conn.commit()
        
        if existing["lat"]:
            print(f"  ✓ {ort_name_clean} (cached)")
            return True
        else:
            # Noch nicht geocodiert, versuchen
            pass
    else:
        # Neuen Ort anlegen
        cursor = conn.execute(
            "INSERT INTO orte (name, vorlage_count) VALUES (?, 1)",
            (ort_name_clean,)
        )
        ort_id = cursor.lastrowid
        conn.execute("""
            INSERT OR IGNORE INTO vorlagen_orte (vorlage_id, ort_id, kontext)
            VALUES (?, ?, ?)
        """, (vorlage_id, ort_id, kontext[:500] if kontext else None))
        conn.commit()
    
    # Geocodieren
    coords = geocode_ort(client, ort_name_clean)
    
    if coords:
        lat, lon = coords
        conn.execute(
            "UPDATE orte SET lat = ?, lon = ?, typ = 'geocoded' WHERE id = ?",
            (lat, lon, ort_id)
        )
        conn.commit()
        print(f"  ✓ {ort_name_clean} → ({lat:.5f}, {lon:.5f})")
        return True
    else:
        print(f"  ✗ {ort_name_clean} (nicht gefunden)")
        return False


def main():
    parser = argparse.ArgumentParser(description="Geocodierung von Orten")
    parser.add_argument("--limit", type=int, default=50, help="Max. Anzahl neuer Orte")
    args = parser.parse_args()
    
    print(f"=== Geocodierung von Orten ===\n")
    
    conn = get_db()
    client = httpx.Client()
    
    # Orte aus KI-Zusammenfassungen extrahieren
    orte = extract_orte_from_ki(conn)
    print(f"Gefunden: {len(orte)} Ort-Erwähnungen\n")
    
    # Deduplizieren
    seen = set()
    unique_orte = []
    for vorlage_id, ort, kontext in orte:
        key = (vorlage_id, ort)
        if key not in seen:
            seen.add(key)
            unique_orte.append((vorlage_id, ort, kontext))
    
    print(f"Unique: {len(unique_orte)} Verknüpfungen\n")
    
    # Verarbeiten
    success = 0
    processed = 0
    for vorlage_id, ort, kontext in unique_orte:
        if processed >= args.limit:
            break
        if process_ort(conn, client, vorlage_id, ort, kontext):
            success += 1
        processed += 1
    
    client.close()
    conn.close()
    
    # Stats
    conn = get_db()
    total_orte = conn.execute("SELECT COUNT(*) FROM orte").fetchone()[0]
    geocoded = conn.execute("SELECT COUNT(*) FROM orte WHERE lat IS NOT NULL").fetchone()[0]
    conn.close()
    
    print(f"\n=== Fertig ===")
    print(f"Orte gesamt: {total_orte}")
    print(f"Geocodiert: {geocoded}")
    print(f"Diese Runde: {success}/{processed}")


if __name__ == "__main__":
    main()
