import sys

from typing import Any, List, Optional, TYPE_CHECKING, Union

if sys.version_info >= (3, 8):
    from typing import Protocol
else:
    from typing_extensions import Protocol

if TYPE_CHECKING:
    from ansi.colour.base import Graphic

CSI = '\x1b['
OSC = '\x1b]'
BEL = '\a'


class SequenceGenerator(Protocol):
    def __call__(self, *vals: Union[int, str, "Graphic"]) -> str: ...


def sequence(letter: str, fields: int = 1,
             default: Optional[List[Union[int, str, "Graphic"]]] = None) -> SequenceGenerator:
    """Create a function that creates escape sequences."""

    def _sequence(*values: Union[int, str, "Graphic"]) -> str:
        output = list(values)
        if fields >= 0 and len(output) > fields:
            raise ValueError('Invalid number of fields, got %d expected %d' %
                             (len(output), fields))

        if default is not None:
            output = output + default[-(fields - len(output)):]

        return ''.join([
            CSI,
            ';'.join(map(str, output)),
            letter,
        ])

    return _sequence


class OSCGenerator(Protocol):
    def __call__(*args: str, **kwargs: Any) -> str: ...


def osc(number: Union[int, str]) -> OSCGenerator:
    """Create a function that creates OSC sequences."""

    def _osc(*args: str, **kwargs: Any) -> str:
        key_value_pairs = ["%s=%s" % (k, v) for (k, v) in kwargs.items()]
        return ''.join([
            OSC,
            str(number),
            ';',
            ';'.join(list(args) + key_value_pairs),
            BEL,
        ])

    return _osc
