from functools import cached_property

from typing import Dict, Iterator, List, Optional, Sequence, Tuple

from pyqgisserver.plugins import plugin_list, plugin_metadata
from pyqgisserver.qgscache.cachemanager import CacheType, get_cacheservice
from qgis.core import QgsProject

from .common import (
    ContextABC,
    ProjectCacheError,
    ServerMetadata,
)

SERVER_CONTEXT_NAME = "Py-QGIS-Server"


class Context(ContextABC):

    def __init__(self):
        self._cm = get_cacheservice()

    @property
    def name(self) -> str:
        return SERVER_CONTEXT_NAME

    @property
    def git_repository_url(self) -> str:
        return "https://github.com/3liz/py-qgis-server"

    @property
    def documentation_url(self) -> str:
        return "https://docs.3liz.org/py-qgis-server/"

    @property
    def search_paths(self) -> List[str]:
        """ Return search paths for projects
        """
        return []

    def project(self, uri: str) -> QgsProject:
        """ Return the project specified by `uri`
        """
        details = self._cm.peek(uri)
        if details:
            return details.project

        # Find by filename
        for cache_t in (CacheType.LRU, CacheType.STATIC):
            for _, d in self._cm.items(cache_t):
                if d.project.fileName() == uri:
                    return d.project

        raise ProjectCacheError(403, f"Project not found in cache: {uri}")

    def installed_plugins(
        self,
        keys: Sequence[str],
        unknown_default: Optional[str] = None,
    ) -> Iterator[Tuple[str, Dict]]:
        """ return installed plugins metadata
        """
        for plugin in plugin_list():
            md = plugin_metadata(plugin)['general']
            yield (
                plugin,
                {k: (md.get(k) or md.get(k.lower(), unknown_default)) for k in keys},
            )

    @cached_property
    def metadata(self) -> ServerMetadata:
        """ Return server metadata
        """
        from pyqgisserver.version import __manifest__, __version__
        return ServerMetadata(
            name=SERVER_CONTEXT_NAME,
            version=__version__,
            build_id=__manifest__.get('buildid'),
            commit_id=__manifest__.get('commitid'),
            is_stable=not any(x in __version__ for x in ("pre", "alpha", "beta", "rc")),
        )
