# Copyright (c) OpenMMLab. All rights reserved.
import re
from functools import wraps
from inspect import isfunction

from importlib_metadata import PackageNotFoundError, distribution
from mmengine.utils import digit_version


def satisfy_requirement(dep):
    pat = '(' + '|'.join(['>=', '==', '>']) + ')'
    parts = re.split(pat, dep, maxsplit=1)
    parts = [p.strip() for p in parts]
    package = parts[0]
    if len(parts) > 1:
        op, version = parts[1:]
        op = {
            '>=': '__ge__',
            '==': '__eq__',
            '>': '__gt__',
            '<': '__lt__',
            '<=': '__le__'
        }[op]
    else:
        op, version = None, None

    try:
        dist = distribution(package)
        if op is None or getattr(digit_version(dist.version), op)(
                digit_version(version)):
            return True
    except PackageNotFoundError:
        pass

    return False


def require(dep, install=None):
    """A wrapper of function for extra package requirements.

    Args:
        dep (str): The dependency package name, like ``transformers``
            or ``transformers>=4.28.0``.
        install (str, optional): The installation command hint. Defaults
            to None, which means to use "pip install dep".
    """

    def wrapper(fn):
        assert isfunction(fn)

        @wraps(fn)
        def ask_install(*args, **kwargs):
            name = fn.__qualname__.replace('.__init__', '')
            ins = install or f'pip install "{dep}"'
            raise ImportError(
                f'{name} requires {dep}, please install it by `{ins}`.')

        if satisfy_requirement(dep):
            fn._verify_require = getattr(fn, '_verify_require', lambda: None)
            return fn

        ask_install._verify_require = ask_install
        return ask_install

    return wrapper


WITH_MULTIMODAL = all(
    satisfy_requirement(item)
    for item in ['pycocotools', 'transformers>=4.28.0'])


def register_multimodal_placeholder(names, registry):
    for name in names:

        def ask_install(*args, **kwargs):
            raise ImportError(
                f'{name} requires extra multi-modal dependencies, please '
                'install it by `pip install "mmpretrain[multimodal]"` '
                'or `pip install -e ".[multimodal]"`.')

        registry.register_module(name=name, module=ask_install)
