"""Google Places sync for Export Intel (optional — requires GOOGLE_MAPS_API_KEY)."""
from __future__ import annotations

import json
import os
import time
from typing import Any, Optional

import httpx

from app.db import fetch_one
from app.export_intel_sync import _get_territory, _upsert_contact

PLACES_URL = "https://maps.googleapis.com/maps/api/place/textsearch/json"
DETAILS_URL = "https://maps.googleapis.com/maps/api/place/details/json"

QUERIES = [
    "meat wholesaler",
    "halal meat distributor",
    "poultry distributor",
    "frozen food supplier",
    "contract catering",
    "food importer",
    "halal butcher",
]

LARGE_COUNTRIES = frozenset({"US", "CA", "BR", "MX", "AR", "AU", "RU", "CN", "IN", "CD", "DZ", "EG", "IR", "SA"})


def _api_key() -> Optional[str]:
    return os.getenv("GOOGLE_MAPS_API_KEY") or os.getenv("GOOGLE_PLACES_API_KEY")


def _places_search(query: str, lat: float, lon: float, radius_m: int = 80000) -> list[dict[str, Any]]:
    key = _api_key()
    if not key:
        return []
    params = {
        "query": query,
        "location": f"{lat},{lon}",
        "radius": radius_m,
        "key": key,
    }
    with httpx.Client(timeout=30.0) as client:
        resp = client.get(PLACES_URL, params=params)
        if resp.status_code >= 400:
            return []
        data = resp.json()
        if data.get("status") not in ("OK", "ZERO_RESULTS"):
            return []
        return data.get("results", [])[:12]


def _place_details(place_id: str) -> dict[str, Any]:
    key = _api_key()
    if not key:
        return {}
    with httpx.Client(timeout=20.0) as client:
        resp = client.get(
            DETAILS_URL,
            params={
                "place_id": place_id,
                "fields": "name,formatted_phone_number,website,formatted_address,geometry,international_phone_number",
                "key": key,
            },
        )
        if resp.status_code >= 400:
            return {}
        return resp.json().get("result", {})


def _bbox_points(bbox: Any, grid: int = 3) -> list[tuple[float, float]]:
    if isinstance(bbox, str):
        bbox = json.loads(bbox)
    if not bbox or len(bbox) != 4:
        return []
    south, west, north, east = bbox
    points: list[tuple[float, float]] = []
    for i in range(grid):
        for j in range(grid):
            lat = south + (north - south) * (i + 0.5) / grid
            lon = west + (east - west) * (j + 0.5) / grid
            points.append((lat, lon))
    return points


def _upsert_place(place: dict[str, Any], details: dict[str, Any], country_iso2: str, territory_code: str, query: str) -> tuple[str, int]:
    from app.db import execute, execute_returning

    pid = place.get("place_id")
    name = details.get("name") or place.get("name") or "Unknown"
    geo = details.get("geometry", {}).get("location", place.get("geometry", {}).get("location", {}))
    plat = geo.get("lat")
    plon = geo.get("lng")
    phone = details.get("formatted_phone_number") or details.get("international_phone_number")
    website = details.get("website")
    entity_type = "contract_caterer" if "catering" in query else "distributor"

    existing = fetch_one(
        "SELECT id FROM export_market_entities WHERE metadata->>'google_place_id' = %s",
        (pid,),
    )
    if existing:
        execute(
            """
            UPDATE export_market_entities SET
                phone = COALESCE(%s, phone), website = COALESCE(%s, website),
                lat = COALESCE(%s, lat), lon = COALESCE(%s, lon),
                confidence = GREATEST(confidence, 65), updated_at = NOW()
            WHERE id = %s
            """,
            (phone, website, plat, plon, existing["id"]),
        )
        entity_id = existing["id"]
        action = "updated"
    else:
        row = execute_returning(
            """
            INSERT INTO export_market_entities (
                name, entity_type, country_iso2, territory_code, lat, lon,
                phone, website, google_place_id, source, sources, confidence, metadata
            ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,'google_places','["google_places"]'::jsonb,65,%s)
            RETURNING id
            """,
            (
                name[:255], entity_type, country_iso2.upper(), territory_code,
                plat, plon, phone, website, pid,
                json.dumps({"google_place_id": pid}),
            ),
        )
        entity_id = row["id"]
        action = "inserted"
    if phone:
        _upsert_contact(entity_id, None, phone, "google_places", 70, role="sales", name="Google Places")
    return action, entity_id


def sync_places_country(country_iso2: str) -> dict[str, Any]:
    territory = _get_territory(country_iso2)
    if not territory or not territory.get("lat"):
        return {"skipped": True, "reason": "no territory"}
    if not _api_key():
        return {"skipped": True, "reason": "GOOGLE_MAPS_API_KEY not set"}

    territory_code = territory["code"]
    inserted = updated = 0
    seen: set[str] = set()

    iso = country_iso2.upper()
    if iso in LARGE_COUNTRIES and territory.get("bbox"):
        search_points = _bbox_points(territory["bbox"], grid=3)
    else:
        search_points = [(territory["lat"], territory["lon"])]

    radius = 60000 if iso in LARGE_COUNTRIES else 80000

    for lat, lon in search_points:
        for q in QUERIES:
            for place in _places_search(q, lat, lon, radius_m=radius):
                pid = place.get("place_id")
                if not pid or pid in seen:
                    continue
                seen.add(pid)
                details = _place_details(pid)
                action, _ = _upsert_place(place, details, iso, territory_code, q)
                if action == "inserted":
                    inserted += 1
                else:
                    updated += 1
                time.sleep(0.15)
            time.sleep(0.5)

    return {"inserted": inserted, "updated": updated, "queries": len(QUERIES), "search_points": len(search_points)}


def sync_places_countries(countries: list[str]) -> dict[str, Any]:
    if not _api_key():
        return {"skipped": True, "reason": "GOOGLE_MAPS_API_KEY not set"}
    out: dict[str, Any] = {}
    for c in countries:
        out[c] = sync_places_country(c)
        time.sleep(1)
    return out
