from typing import Mapping
from typing import Any


def with_extra_spec_options(
    original: Mapping[str, Any],
    extra_options: Mapping[str, Any],
    context: str,
) -> Mapping[str, Any]:
    """
    Given an original arbitrary spec and a set of overrides, verify the overrides don't intersect with the existing attributes and return both mappings merged.

    Parameters
    ----------
    original
        Original map of key-values.

    extra_options
        Options to set.

    context
        Context in which this options are being set. This is used to produce a useful error message.


    Raises
    ------
    ValueError
        If we attempt to override keys that are already present in the original mapping.
    """
    spec = {**original}

    for key_to_override, overridden_value in extra_options.items():
        this_context = ".".join([context, key_to_override])

        if key_to_override not in spec:
            spec[key_to_override] = overridden_value
        elif isinstance(spec[key_to_override], list) and isinstance(
            overridden_value, list
        ):
            spec[key_to_override] += overridden_value
        elif isinstance(spec[key_to_override], dict) and isinstance(
            overridden_value, dict
        ):
            spec[key_to_override] = with_extra_spec_options(
                original=spec[key_to_override],
                extra_options=overridden_value,
                context=this_context,
            )
        else:
            raise ValueError(
                f"You are trying to override the value of '{this_context}'. The Argo runtime already sets a value for this key, and it uses it to guarantee the correctness of the behavior. Therefore, we cannot let you override them."
            )

    return spec