# Copyright (C) 2019-2021 HERE Global B.V. and its affiliate(s).
# All rights reserved.
#
# This software and other materials contain proprietary information
# controlled by HERE and are protected by applicable copyright legislation.
# Any use and utilization of this software and other materials and
# disclosure to any third parties is conditional upon having a separate
# agreement with HERE for the access, use, utilization or disclosure of this
# software. In the absence of such agreement, the use of the software is not
# allowed.

"""
Features related to HERE basemaps.
"""

import random
from typing import Optional
from urllib.parse import urlencode

import here.inspector
import requests
from traitlets.utils.bunch import Bunch


def get_tiletypes_schemes(service: str, api_key: Optional[str] = None) -> dict:
    """Return a dict with tiletypes and schemes for some HERE basemap service.

    :param service: Service name, either "aerial", "base" or "traffic".
    :param api_key: The classic API key, included with a registration on
        http://developer.here.com. If not specified the value will be looked
        up in ``here.inspector.options.api_key``.
    :return: A dictionary.

    Example:

    >>> get_tiletypes_schemes("aerial", api_key="***")  # doctest: +SKIP
    {'tiletypes': ["maptile", ...], 'schemes': ["terrain.day", ...]}
    """  # noqa: D412
    s = random.randint(1, 4)
    params = {"output": "json"}
    info_url = f"https://{s}.{service}.maps.ls.hereapi.com/maptile/2.1/info"
    params["apiKey"] = api_key or here.inspector.options.api_key  # type: ignore
    info = requests.get(info_url, params=params).json()
    tiletypes = [tt["id"] for tt in info["response"]["tiletypes"]["tiletype"]]
    schemes = [sch["id"] for sch in info["response"]["schemes"]["scheme"]]
    return dict(tiletypes=tiletypes, schemes=schemes)


def make_basemap(
    service: str = "aerial",
    tile_type: str = "maptile",
    scheme: str = "terrain.day",
    format: str = "png",
    size: int = 256,
    max_zoom: int = 20,
    name: Optional[str] = None,
    api_key: Optional[str] = None,
    options: Optional[dict] = None,
) -> dict:
    """Return a dictionary for one parameterized basemap including a tiles URL.

    :param service: The maptile service name, "aerial" or "traffic".
    :param tile_type: The tile type, default: "maptile".
    :param scheme: The tile scheme, default: "terrain.day".
    :param format: The tile bitmap format, "png" (default) or "jpeg".
    :param size: The tile size, default: 256.
    :param max_zoom: The max. zoom level, default: 20.
    :param name: A string that can be helpful in UI widgets.
    :param options: A dict with additional key/value parameters for the basemap.
    :param api_key: The classic API key, included with a registration on
        http://developer.here.com. If not specified the value will be looked
        up in ``here.inspector.options.api_key``.
    :return: A dictionary representing one basemap.
    """
    api_key = api_key or here.inspector.options.api_key or "_APIKEY_"  # type: ignore
    s = random.randint(1, 4)
    url = (
        f"https://{s}.{service}.maps.ls.hereapi.com/maptile/2.1"
        f"/{tile_type}/newest/{scheme}/{{z}}/{{x}}/{{y}}/{size}/{format}?apiKey={api_key}"
    )
    if options:
        url += f"&{urlencode(options)}"
    return {
        "url": url,
        "max_zoom": max_zoom,
        "attribution": '<a href="https://here.com">HERE.com</a>',
        "name": name or f"Here / {service} / {tile_type} / {scheme}",
    }


def make_basemaps(api_key: Optional[str] = None, options={}) -> Bunch:
    """Return a `:class:Bunch` of basemaps.

    :param api_key: The classic API key, included with a registration on
        http://developer.here.com. If not specified the value will be looked
        up in ``here.inspector.options.api_key``.
    :param options: A dictionary with additional parameters specifying
        further details of the basemaps, e.g. ``"lg": "ita"`` to have
        labels in Italian.
    :return: A collection of parameterized basemaps.
    """
    basemaps = Bunch()
    for service in ["aerial", "base", "traffic"]:
        res = get_tiletypes_schemes(service, api_key=api_key)
        tiletypes = res["tiletypes"]
        schemes = res["schemes"]
        basemaps[service] = Bunch(
            {
                tt: Bunch(
                    {
                        sch.replace(".", "_"): make_basemap(
                            service=service,
                            tile_type=tt,
                            scheme=sch,
                            api_key=api_key,
                            options=options,
                        )
                        for sch in schemes
                    }
                )
                for tt in tiletypes
            }
        )
    return basemaps
