"""
Nominatim Client for geocoding and address search
"""

import structlog
import httpx
from typing import Optional, List, Dict, Any
from shared.config.base import BaseServiceSettings

logger = structlog.get_logger()


class NominatimClient:
    """
    Client for Nominatim geocoding service.

    Provides address search and geocoding capabilities for the bakery onboarding flow.
    """

    def __init__(self, config: BaseServiceSettings):
        self.config = config
        self.nominatim_url = getattr(
            config,
            "NOMINATIM_SERVICE_URL",
            "http://nominatim-service:8080"
        )
        self.timeout = 30

    async def search_address(
        self,
        query: str,
        country_codes: str = "es",
        limit: int = 5,
        addressdetails: bool = True
    ) -> List[Dict[str, Any]]:
        """
        Search for addresses matching a query.

        Args:
            query: Address search query (e.g., "Calle Mayor 1, Madrid")
            country_codes: Limit search to country codes (default: "es" for Spain)
            limit: Maximum number of results (default: 5)
            addressdetails: Include detailed address breakdown (default: True)

        Returns:
            List of geocoded results with lat, lon, and address details

        Example:
            results = await nominatim.search_address("Calle Mayor 1, Madrid")
            if results:
                lat = results[0]["lat"]
                lon = results[0]["lon"]
                display_name = results[0]["display_name"]
        """
        try:
            async with httpx.AsyncClient(timeout=self.timeout) as client:
                response = await client.get(
                    f"{self.nominatim_url}/search",
                    params={
                        "q": query,
                        "format": "json",
                        "countrycodes": country_codes,
                        "addressdetails": 1 if addressdetails else 0,
                        "limit": limit
                    }
                )

                if response.status_code == 200:
                    results = response.json()
                    logger.info(
                        "Address search completed",
                        query=query,
                        results_count=len(results)
                    )
                    return results
                else:
                    logger.error(
                        "Nominatim search failed",
                        query=query,
                        status_code=response.status_code,
                        response=response.text
                    )
                    return []

        except httpx.TimeoutException:
            logger.error("Nominatim search timeout", query=query)
            return []
        except Exception as e:
            logger.error("Nominatim search error", query=query, error=str(e))
            return []

    async def geocode_address(
        self,
        street: str,
        city: str,
        postal_code: Optional[str] = None,
        country: str = "Spain"
    ) -> Optional[Dict[str, Any]]:
        """
        Geocode a structured address to coordinates.

        Args:
            street: Street name and number
            city: City name
            postal_code: Optional postal code
            country: Country name (default: "Spain")

        Returns:
            Dict with lat, lon, and display_name, or None if not found

        Example:
            location = await nominatim.geocode_address(
                street="Calle Mayor 1",
                city="Madrid",
                postal_code="28013"
            )
            if location:
                lat, lon = location["lat"], location["lon"]
        """
        # Build structured query
        query_parts = [street, city]
        if postal_code:
            query_parts.append(postal_code)
        query_parts.append(country)

        query = ", ".join(query_parts)

        results = await self.search_address(query, limit=1)
        if results:
            return results[0]
        return None

    async def reverse_geocode(
        self,
        latitude: float,
        longitude: float
    ) -> Optional[Dict[str, Any]]:
        """
        Reverse geocode coordinates to an address.

        Args:
            latitude: Latitude coordinate
            longitude: Longitude coordinate

        Returns:
            Dict with address details, or None if not found

        Example:
            address = await nominatim.reverse_geocode(40.4168, -3.7038)
            if address:
                city = address["address"]["city"]
                street = address["address"]["road"]
        """
        try:
            async with httpx.AsyncClient(timeout=self.timeout) as client:
                response = await client.get(
                    f"{self.nominatim_url}/reverse",
                    params={
                        "lat": latitude,
                        "lon": longitude,
                        "format": "json",
                        "addressdetails": 1
                    }
                )

                if response.status_code == 200:
                    result = response.json()
                    logger.info(
                        "Reverse geocoding completed",
                        lat=latitude,
                        lon=longitude
                    )
                    return result
                else:
                    logger.error(
                        "Nominatim reverse geocoding failed",
                        lat=latitude,
                        lon=longitude,
                        status_code=response.status_code
                    )
                    return None

        except Exception as e:
            logger.error(
                "Reverse geocoding error",
                lat=latitude,
                lon=longitude,
                error=str(e)
            )
            return None

    async def health_check(self) -> bool:
        """
        Check if Nominatim service is healthy.

        Returns:
            True if service is responding, False otherwise
        """
        try:
            async with httpx.AsyncClient(timeout=5) as client:
                response = await client.get(f"{self.nominatim_url}/status")
                return response.status_code == 200
        except Exception as e:
            logger.warning("Nominatim health check failed", error=str(e))
            return False
