from __future__ import annotations

from typing import Dict, Type, TypeVar

from .._compat import get_args, get_origin, is_generic


def generate_mapping(cl: Type, old_mapping: Dict[str, type] = {}) -> Dict[str, type]:
    mapping = {}

    origin = get_origin(cl)

    if origin is not None:
        # To handle the cases where classes in the typing module are using
        # the GenericAlias structure but aren’t a Generic and hence
        # end up in this function but do not have an `__parameters__`
        # attribute. These classes are interface types, for example
        # `typing.Hashable`.
        parameters = getattr(get_origin(cl), "__parameters__", None)
        if parameters is None:
            return dict(old_mapping)

        for p, t in zip(parameters, get_args(cl)):
            if isinstance(t, TypeVar):
                continue
            mapping[p.__name__] = t

        if not mapping:
            return dict(old_mapping)
    elif is_generic(cl):
        # Origin is None, so this may be a subclass of a generic class.
        orig_bases = cl.__orig_bases__
        for base in orig_bases:
            if not hasattr(base, "__args__"):
                continue
            base_args = base.__args__
            if not hasattr(base.__origin__, "__parameters__"):
                continue
            base_params = base.__origin__.__parameters__
            for param, arg in zip(base_params, base_args):
                mapping[param.__name__] = arg

    return mapping
