# -*- coding: utf-8 -*-
#
# Copyright (C) 2021 TU Wien.
#
# Invenio-Requests is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.

"""Registry for easy access to the registered entity resolvers."""

from invenio_access.permissions import system_process

from ..proxies import current_requests


class ResolverRegistry:
    """Namespace for resolver functions."""

    @classmethod
    def get_registered_resolvers(cls):
        """Get all currently registered resolvers."""
        return iter(current_requests.entity_resolvers_registry)

    @classmethod
    def resolve_entity_proxy(cls, reference_dict, raise_=False):
        """Get a proxy for the referenced entity via the configured resolvers.

        If `REQUESTS_ENTITY_RESOLVERS` does not contain a matching EntityResolver
        for the given `reference_dict`, the `raise_` parameter determines whether
        a `ValueError` is raised or `None` is returned.
        """
        for resolver in cls.get_registered_resolvers():
            if resolver.matches_reference_dict(reference_dict):
                return resolver.get_entity_proxy(reference_dict, check=False)

        if raise_:
            raise ValueError(f"No matching resolver registered for: {reference_dict}")

        return None

    @classmethod
    def resolve_entity(cls, reference_dict, raise_=False):
        """Resolve the referenced entity via the configured resolvers.

        This calls `resolve_entity_proxy()` and then `resolve()` on the proxy.
        Note that this may create an expensive lookup, like a DB query.
        """
        proxy = cls.resolve_entity_proxy(reference_dict, raise_=raise_)

        if proxy is None:
            return None

        return proxy.resolve()

    @classmethod
    def resolve_need(cls, reference_dict, raise_=False):
        """Get the need for the referenced entity via the configured resolvers.

        This calls `resolve_entity_proxy()` and then `get_need()` on the proxy.
        Note: If the concept of needs is not applicable to the referenced type of
        entity (e.g. `Request`), `None` is returned.
        """
        proxy = cls.resolve_entity_proxy(reference_dict, raise_=raise_)

        if proxy is None:
            return None

        return proxy.get_need()

    @classmethod
    def reference_entity(cls, entity, raise_=False):
        """Create a reference dict for the given entity via the configured resolvers.

        If `REQUESTS_ENTITY_RESOLVERS` does not contain a matching EntityResolver
        for the given `entity`, the `raise_` parameter determines whether a `ValueError`
        is raised or `None` is returned.
        """
        for resolver in cls.get_registered_resolvers():
            if resolver.matches_entity(entity):
                return resolver.reference_entity(entity, check=False)

        if raise_:
            raise ValueError(f"No matching resolver registered for: {type(entity)}")

        return None

    @classmethod
    def reference_identity(cls, identity, raise_=False):
        """Create a reference dict for the user behind the given identity."""
        if system_process in identity.provides:
            return None

        return {"user": str(identity.id)}
