from typing import Any
from typing import Union
import re


def replace_variables(
    input_string: str, interface: Any, key: Union[int, None] = None
) -> str:
    """
    In a string, attempt to replace all the "$$X" variables with their
    definitions from the interface. If not found in the interface, it skips the
    variable, leaving it to the user to replace afterwards

    Args:
        input_string (str): String containing $$X variables
        interface (Any): An interface
        key (Union[int, None], optional): If the replacement string is a data
            structure, use this key to index it. Defaults to None.

    Returns:
        str: Updated string
    """

    regex_variable = re.compile(r"\$\$[^_|\W]+")
    for variable in re.findall(regex_variable, input_string):
        try:
            new_variable = getattr(interface, variable[2:])
        except AttributeError:
            continue
        else:
            if isinstance(new_variable, (list, tuple)):
                if key is None:
                    raise ValueError
                new_variable = new_variable[key]
            input_string = input_string.replace(variable, str(new_variable))

    return input_string