from typing import List
from typing import Tuple
import re


def expand_string(string: str, to_replace: List[Tuple[str, str]]) -> str:
    """
    Within string replace a character in the first value of a pair to the second value of a pair.
    If the string contains the character in the second value, the character will be doubled.

    :param string:
    :param to_replace: the mapping between character to replace and what are the substitutes. Mapping
    must be unique. The mapping ordered **is important**.

    :return: the string replaced
    """

    # keys must be unique
    if len(set(map(lambda x: x[0], to_replace))) < len(to_replace):
        raise ValueError(f"2 keys are the same!")
    # vlaues must be uniqye
    if len(set(map(lambda x: x[1], to_replace))) < len(to_replace):
        raise ValueError(f"2 values are the same!")

    # clean the string from any replacement character
    for i, (_, replacement) in enumerate(to_replace):
        if replacement in string:
            # replacement will be "XX" or "XXX" or "XXXX" but we endure it will never be "X"
            string = string.replace(replacement, replacement * (i+2))

    # ok, now we're sure that string does not contain single replacement characters
    for i, (to_replace_char, replacement) in enumerate(to_replace):
        if re.search(to_replace_char * 2, string) is not None:
            raise ValueError(f"value to replace {to_replace} is present twice contigouosly in string {string}!")
        if to_replace_char in string:
            string = string.replace(to_replace_char, replacement)

    return string