"""CFNgin lookup registry."""
import logging
import warnings

from six import string_types

from runway.lookups.handlers import ssm
from runway.util import load_object_from_string

from ..exceptions import FailedVariableLookup, UnknownLookupType
from .handlers import ami, default, dynamodb, envvar
from .handlers import file as file_handler
from .handlers import hook_data, kms, output, rxref, split, ssmstore, xref

CFNGIN_LOOKUP_HANDLERS = {}


def register_lookup_handler(lookup_type, handler_or_path):
    """Register a lookup handler.

    Args:
        lookup_type (str): Name to register the handler under.
        handler_or_path (Union[Callable, str]): A function or a path to a
            handler.

    """
    handler = handler_or_path
    if isinstance(handler_or_path, string_types):
        handler = load_object_from_string(handler_or_path)
    CFNGIN_LOOKUP_HANDLERS[lookup_type] = handler
    if not isinstance(handler, type):
        # Hander is a not a new-style handler
        logger = logging.getLogger(__name__)
        logger.warning("Registering lookup `%s`: Please upgrade to use the "
                       "new style of Lookups.", lookup_type)
        warnings.warn(
            # For some reason, this does not show up...
            # Leaving it in anyway
            "Lookup `%s`: Please upgrade to use the new style of Lookups"
            "." % lookup_type,
            DeprecationWarning,
            stacklevel=2,
        )


def unregister_lookup_handler(lookup_type):
    """Unregister the specified lookup type.

    This is useful when testing various lookup types if you want to unregister
    the lookup type after the test runs.

    Args:
        lookup_type (str): Name of the lookup type to unregister.

    """
    CFNGIN_LOOKUP_HANDLERS.pop(lookup_type, None)


def resolve_lookups(variable, context, provider):
    """Resolve a set of lookups.

    Args:
        variable (:class:`runway.cfngin.variables.Variable`): The variable
            resolving it's lookups.
        context (:class:`runway.cfngin.context.Context`): Context instance.
        provider (:class:`runway.cfngin.providers.base.BaseProvider`): Provider
            instance.

    Returns:
        Dict[str, Any]: Lookup -> resolved value

    """
    resolved_lookups = {}
    for lookup in variable.lookups:
        try:
            handler = CFNGIN_LOOKUP_HANDLERS[lookup.type]
        except KeyError:
            raise UnknownLookupType(lookup)
        try:
            resolved_lookups[lookup] = handler(
                value=lookup.input,
                context=context,
                provider=provider,
            )
        except Exception as err:
            raise FailedVariableLookup(variable.name, lookup, err)
    return resolved_lookups


register_lookup_handler(ami.TYPE_NAME, ami.AmiLookup)
register_lookup_handler(default.TYPE_NAME, default.DefaultLookup)
register_lookup_handler(dynamodb.TYPE_NAME, dynamodb.DynamodbLookup)
register_lookup_handler(envvar.TYPE_NAME, envvar.EnvvarLookup)
register_lookup_handler(file_handler.TYPE_NAME, file_handler.FileLookup)
register_lookup_handler(hook_data.TYPE_NAME, hook_data.HookDataLookup)
register_lookup_handler(kms.TYPE_NAME, kms.KmsLookup)
register_lookup_handler(output.TYPE_NAME, output.OutputLookup)
register_lookup_handler(rxref.TYPE_NAME, rxref.RxrefLookup)
register_lookup_handler(split.TYPE_NAME, split.SplitLookup)
register_lookup_handler(ssm.TYPE_NAME, ssm.SsmLookup)
register_lookup_handler(ssmstore.TYPE_NAME, ssmstore.SsmstoreLookup)
register_lookup_handler(xref.TYPE_NAME, xref.XrefLookup)
