#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
[CYBER-STRAT] Agent Geo-Intelligence — Resolution geospatiale des entites
urllib.request uniquement (zero import requests)
"""

import json
import urllib.request
import urllib.parse
import time

NOMINATIM_API = "https://nominatim.openstreetmap.org/search"
NOMINATIM_DELAY = 1.1  # Respect politique Nominatim (1 req/sec max)

HEADERS = {
    "User-Agent": "CyberStrat/1.0 (console-intelligence-geopolitique; educational)"
}

# Zoom Leaflet recommande par type d'entite
ZOOM_LEVELS = {
    "country": 5,
    "person": 8,
    "organization": 12,
    "concept": 4,
    "city": 11,
    "region": 7
}

# Types qui declenchent une carte Leaflet (vs simple affichage coordonnees)
MAP_ENTITY_TYPES = {"country", "city", "region"}


def _log(level, message):
    print(f"[CYBER-STRAT][GEO][{level}] {message}")


class GeoResolver:
    """Resolution geospatiale des entites via Nominatim (OpenStreetMap)"""

    def resolve(self, query, entity_type="concept"):
        """Resout une entite en coordonnees GPS via Nominatim.
        Retourne un dict avec lat, lon, label, zoom, display_mode ou None.
        """
        time.sleep(NOMINATIM_DELAY)

        params_dict = {
            "q": query,
            "format": "json",
            "limit": "3",
            "accept-language": "fr"
        }

        # Pour les pays, demander explicitement le featuretype et plus de candidats
        if entity_type == "country":
            params_dict["featuretype"] = "country"
            params_dict["limit"] = "5"

        params = urllib.parse.urlencode(params_dict)
        url = f"{NOMINATIM_API}?{params}"

        try:
            req = urllib.request.Request(url, headers=HEADERS)
            with urllib.request.urlopen(req, timeout=10) as resp:
                results = json.loads(resp.read().decode("utf-8"))

            if not results:
                _log("WARN", f"Aucun resultat geo pour '{query}'")
                return None

            # Pour les pays, filtrer pour privilegier les vrais pays (relations OSM)
            if entity_type == "country":
                best = self._select_best_country(results, query)
            else:
                best = results[0]
            display_mode = "map" if entity_type in MAP_ENTITY_TYPES else "coords"

            geo_data = {
                "lat": float(best["lat"]),
                "lon": float(best["lon"]),
                "label": best.get("display_name", query).split(",")[0].strip(),
                "full_label": best.get("display_name", query),
                "zoom": ZOOM_LEVELS.get(entity_type, 5),
                "display_mode": display_mode,
                "bbox": best.get("boundingbox"),
            }

            _log("INFO", f"Geo resolu: '{query}' -> {geo_data['lat']}, {geo_data['lon']} ({display_mode})")
            return geo_data

        except Exception as e:
            _log("ERROR", f"Erreur resolution geo '{query}': {e}")
            return None

    def _select_best_country(self, results, query):
        """Selectionne le meilleur resultat pays parmi les candidats Nominatim.

        Prefere les resultats avec osm_type='relation', class='boundary',
        type='administrative' (signature d'un vrai pays dans OSM).
        En cas de multiples candidats, prend celui avec l'importance la plus haute.
        Fallback sur results[0] si aucun candidat ne passe le filtre.
        """
        country_candidates = [
            r for r in results
            if r.get("osm_type") == "relation"
            and r.get("class") == "boundary"
            and r.get("type") == "administrative"
        ]

        if country_candidates:
            best = max(country_candidates, key=lambda r: float(r.get("importance", 0)))
            _log("INFO", f"Filtre pays: {len(country_candidates)} candidat(s) sur "
                         f"{len(results)} resultats pour '{query}' — "
                         f"selection: '{best.get('display_name', '?')}'")
            return best

        _log("WARN", f"Aucun candidat boundary/administrative pour '{query}', "
                      f"fallback sur premier resultat")
        return results[0]

    def build_leaflet_config(self, geo_data, entity_name):
        """Construit la configuration Leaflet pour le front-end"""
        if not geo_data:
            return None

        return {
            "center": [geo_data["lat"], geo_data["lon"]],
            "zoom": geo_data.get("zoom", 5),
            "markers": [
                {
                    "lat": geo_data["lat"],
                    "lon": geo_data["lon"],
                    "label": entity_name,
                    "popup": geo_data.get("label", entity_name)
                }
            ],
            "tile_layer": {
                "url": "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
                "attribution": "CartoDB Dark Matter",
                "subdomains": "abcd"
            }
        }
