"""General decorators and helper methods which should not import ee."""

import functools
from typing import Any
from collections.abc import Callable


def accept_opt_prefix(*opt_args) -> Callable[..., Any]:
  """Decorator to maintain support for "opt_" prefixed kwargs.

  Args:
    *opt_args: Arguments prefixed with "opt_" to be replaced by the stripped
      version. Use a nested tuple to map an old "opt_" arg to a new one, e.g.,
      `opt_my_arg, (opt_my_arg2, opt_new_name)`.

  Returns:
    The decorated function which accepts the "opt_" versions of the args.
  """
  args_map = dict()
  for arg in opt_args:
    if isinstance(arg, str):
      args_map[arg] = arg.replace('opt_', '', 1)
    elif isinstance(arg, tuple):
      opt_arg, new_arg = arg
      args_map[opt_arg] = new_arg

  def opt_fixed(func: Callable[..., Any]):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
      # Cache the kwarg keys, since kwargs will be modified.
      for key in list(kwargs):
        if key in args_map:
          new_key = args_map.get(key)
          # Remove the old key unconditionally.
          old_key_val = kwargs.pop(key)
          # Ensure that existing keys are not overridden.
          if new_key not in kwargs:
            kwargs[new_key] = old_key_val
      return func(*args, **kwargs)

    return wrapper

  return opt_fixed
