from typing import Literal, Optional, Union, cast, Tuple, get_args

TSystemModifiers = Literal["ctrl", "shift", "alt", "meta"]
TModifierGuards = Literal[
    "shift",
    "ctrl",
    "alt",
    "meta",
    "left",
    "right",
    "stop",
    "prevent",
    "self",
    "middle",
    "exact",
]
TCompatModifiers = Literal["esc", "space", "up", "left", "right", "down", "delete"]

TOtherModifier = Literal["passive", "capture", "once"]


TEventModifier = Union[
    TSystemModifiers, TModifierGuards, TCompatModifiers, TOtherModifier
]


def _get_valid_modifiers() -> set[str]:
    modifiers: set[str] = set()
    event_modifier_args = get_args(TEventModifier)
    for arg in event_modifier_args:
        if hasattr(arg, "__origin__") and arg.__origin__ is Literal:
            modifiers.update(get_args(arg))
        else:
            modifiers.add(arg)
    return modifiers


VALID_MODIFIERS = _get_valid_modifiers()


def parse_event_components(
    event_name: str,
    org_modifier: Optional[list[TEventModifier]] = None,
    org_with_keys: Optional[list[str]] = None,
) -> Tuple[str, Optional[list[TEventModifier]], Optional[list[str]]]:
    """Parse event name, modifiers and with_keys from event_name string and optional lists.

    Args:
        event_name: Event name string, may contain modifiers and keys separated by dots
                    (e.g. 'click.ctrl.shift.a.b')
        org_modifier: Optional list of additional modifiers
        org_with_keys: Optional list of additional with_keys

    Returns:
        Tuple of (cleaned_event_name, combined_modifiers, combined_with_keys) where:
            - cleaned_event_name: event name without modifiers and keys
            - combined_modifiers: tuple of unique modifiers from both sources
            - combined_with_keys: tuple of unique with_keys from both sources
    """
    parts = event_name.split(".")
    base_name = parts[0]
    remaining = parts[1:] if len(parts) > 1 else []

    modifiers: set[str] = set()
    with_keys: set[str] = set()

    for token in remaining:
        if token in VALID_MODIFIERS:
            modifiers.add(token)
        else:
            with_keys.add(token)

    if org_modifier:
        modifiers.update(org_modifier)

    if org_with_keys:
        with_keys.update(org_with_keys)

    return (
        base_name,
        cast(list[TEventModifier], list(modifiers)) if modifiers else None,
        list(with_keys) if with_keys else None,
    )
