# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/datasets/coords.ipynb.

# %% auto 0
__all__ = ['platform', 'hostname', 'memory', 'get_coords_cache_path', 'get_lat_lon']

# %% ../../nbs/datasets/coords.ipynb 3
import getpass
import socket
import sys
from pathlib import Path
from typing import Dict, Optional

import yaml
from joblib import Memory
from loguru import logger

import enilm.config_file
import enilm.etypes
from . import get_nilmtk_dataset

# %% ../../nbs/datasets/coords.ipynb 6
def _query_lat_lon(query: str | Dict) -> Optional[tuple[float, float]]:
    try:
        from geopy.geocoders import Nominatim
        from geopy.exc import GeocoderTimedOut, GeocoderUnavailable
    except ImportError as e:
        logger.warning(f"Error while importing geopy: {e}")
        logger.warning("Please install geopy using 'pip install geopy'")
        return None

    try:
        geolocator = Nominatim(user_agent="enilm")
        location = geolocator.geocode(query)
        if location:
            return (location.latitude, location.longitude)  # type: ignore
        else:
            return None
    except (GeocoderTimedOut, GeocoderUnavailable) as e:
        logger.warning(f"Geocoding service unavailable or request timed out: {e}")
        return None
    except Exception as e:
        logger.warning(f"Error while getting lat/lon for {query}: {e}")
        return None

# %% ../../nbs/datasets/coords.ipynb 13
# get device info
platform = sys.platform
hostname = socket.gethostname()
try:
    username = getpass.getuser()
except KeyError:
    username = None

# %% ../../nbs/datasets/coords.ipynb 16
def get_coords_cache_path() -> Path:
    config_file_path = enilm.config_file.get_config_file_path()

    assert isinstance(config_file_path, Path)
    coords_cache_paths = yaml.safe_load(config_file_path.read_text())["paths"][
        "coords_cache"
    ]

    if platform in coords_cache_paths:
        found_platform_paths = coords_cache_paths[platform]

        # accept default if no hostname is specified
        found_hostname = False
        if not hostname in found_platform_paths and "default" in found_platform_paths:
            found_host_paths = found_platform_paths["default"]
            found_hostname = True
        elif hostname in found_platform_paths:
            found_host_paths = found_platform_paths[hostname]
            found_hostname = True

        if found_hostname:
            if username in found_host_paths:
                found_path = Path(found_host_paths[username])
                if not found_path.exists():
                    found_path.mkdir(parents=True, exist_ok=True)
                return found_path

    raise ValueError(
        f"Could not find a path for platform '{platform}', hostname '{hostname}', username '{username}' in {config_file_path}"
    )

# %% ../../nbs/datasets/coords.ipynb 18
memory = Memory(get_coords_cache_path(), verbose=0)


@memory.cache
def get_lat_lon(
    ds: enilm.etypes.DatasetID,
    try_auto_retrive: bool = True,
) -> Optional[tuple[float, float]]:
    """Get the lat/lon of a dataset if available in the metadata.
    If not, try to get it from the country or timezone.

    Args:
        ds (enilm.etypes.DatasetID): _description_
        try_auto_retrive (bool, optional): try of to get a lat/long even if not available in the metadata (not as accuracte). Defaults to True.

    Returns:
        Optional[tuple[float, float]]: lat/lon as a tuple if available/found, None otherwise
    """

    ds_nilmtk = None
    try:
        ds_nilmtk = get_nilmtk_dataset(ds)
    except AttributeError as e:
        logger.warning(f"Error while getting nilmtk dataset for {ds}: {e}")

    if ds_nilmtk is not None:
        ds_metadata = None
        try:
            ds_metadata = ds_nilmtk.metadata
        except AttributeError as e:
            logger.warning(f"Error while getting metadata for {ds}: {e}")

        if ds_metadata is not None:
            can_get_from_metadata = False
            geo_data = ds_metadata.get("geo_location", None)
            if geo_data is not None:
                lat = geo_data.get("latitude", None)
                lon = geo_data.get("longitude", None)
                if lat is not None and lon is not None:
                    can_get_from_metadata = True

            if can_get_from_metadata:
                return lat, lon

            if try_auto_retrive:
                # saved?
                # country -> capital
                if geo_data is not None and "country" in geo_data:
                    country = geo_data["country"]
                    possible_cap_lat_lon = _query_lat_lon({"country": country})
                    if possible_cap_lat_lon is not None:
                        logger.info(f"Got lat/lon from capital of {country}")
                        return possible_cap_lat_lon

                # from timezone?
                if "timezone" in ds_metadata:
                    timezone = ds_metadata["timezone"]
                    city = timezone.split("/")[1]
                    if city:
                        possible_tz_lat_lon = _query_lat_lon({"city": city})
                        if possible_tz_lat_lon is not None:
                            logger.info(f"Got lat/lon from timezone of {city}")
                            return possible_tz_lat_lon

    return None
