# Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.  Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#
import asyncio
import json
import logging
import os
from functools import lru_cache
from typing import Callable, List

import omni.kit.app

from .common import ExtensionCommonInfo, get_registry_url

logger = logging.getLogger(__name__)


class ExtDataFetcher:
    """Fetches json files near extension archives from the registry and caches them"""

    def __init__(self):
        # Notify when anything new fetched
        self.on_data_fetched_fn: Callable = None

        # Cached data
        self._data = {}

    def get_ext_data(self, package_id) -> dict:
        return self._data.get(package_id, None)

    def fetch(self, ext_item: ExtensionCommonInfo):
        if self.get_ext_data(ext_item.package_id):
            return
        json_data_urls = self._build_json_data_urls(ext_item)
        if json_data_urls:

            async def read_data():
                for json_data_url in json_data_urls:
                    result, _, content = await omni.client.read_file_async(json_data_url)
                    if result == omni.client.Result.OK:
                        try:
                            content = memoryview(content).tobytes().decode("utf-8")
                            self._data[ext_item.package_id] = json.loads(content)
                            if self.on_data_fetched_fn:
                                self.on_data_fetched_fn(ext_item.package_id)  # noqa
                            break
                        except Exception as e:  # noqa
                            logger.error("Error reading extra registry data from: %s. Error: %s", json_data_url, e)

            asyncio.ensure_future(read_data())

    def _build_json_data_urls(self, ext_item: ExtensionCommonInfo) -> List[str]:
        ext_manager = omni.kit.app.get_app().get_extension_manager()
        ext_remote_info = ext_manager.get_registry_extension_dict(ext_item.package_id)
        registry_url = get_registry_url(ext_item.provider_name)
        if not registry_url:
            return None

        # Same as archive path, but extension is `.json`:
        archive_path = ext_remote_info.get("package", {}).get("archivePath", None)
        if archive_path:
            # build url relative to the registry url
            archive_path = archive_path.replace("\\", "/")
            archive_path = omni.client.combine_urls(registry_url + "/index.zip", archive_path)
            archive_path = omni.client.normalize_url(archive_path)
            archive_path = os.path.splitext(archive_path)[0] + ".json"

            if omni.client.break_url(archive_path).host == omni.client.break_url(registry_url).host:
                return [archive_path]

            # that means archive path is on different host (like packman). Do the best guess using registry url.
            # Old format is one big folder, new format is a subfolder for each extension
            data_filename = os.path.basename(archive_path)
            return [
                "{}/archives/{}".format(registry_url, data_filename),
                "{}/archives/{}/{}".format(registry_url, ext_item.fullname, data_filename),
            ]

        return None


@lru_cache()
def get_ext_data_fetcher():
    return ExtDataFetcher()
