from transitions_aio import Machine

try:
    from anyio import get_cancelled_exc_class
    from sniffio import AsyncLibraryNotFoundError  # type: ignore[import-untyped]
except ImportError:
    pass


class Stuff(object):

    is_false = False
    is_True = True

    def __init__(self, states=None, machine_cls=Machine, extra_kwargs=None):
        extra_kwargs = extra_kwargs if extra_kwargs is not None else {}

        self.state = None
        self.message = None
        states = ['A', 'B', 'C', 'D', 'E', 'F'] if states is None else states

        args = [self]
        kwargs = {
            'states': states,
            'initial': 'A',
            'name': 'Test Machine',
        }
        kwargs.update(extra_kwargs)
        if machine_cls is not None:
            self.machine = machine_cls(*args, **kwargs)
        self.level = 1
        self.transitions = 0
        self.machine_cls = machine_cls

    @staticmethod
    def this_passes():
        return True

    @staticmethod
    def this_fails():
        return False

    @staticmethod
    def this_raises(exception, *args, **kwargs):
        raise exception

    @staticmethod
    def this_fails_by_default(boolean=False):
        return boolean

    @staticmethod
    def extract_boolean(event_data):
        return event_data.kwargs['boolean']

    def goodbye(self):
        self.message = "So long, suckers!"

    def hello_world(self):
        self.message = "Hello World!"

    def greet(self):
        self.message = "Hi"

    def meet(self):
        self.message = "Nice to meet you"

    def hello_F(self):
        if self.message is None:
            self.message = ''
        self.message += "Hello F!"

    def increase_level(self):
        self.level += 1
        self.transitions += 1

    def decrease_level(self):
        self.level -= 1
        self.transitions += 1

    def set_message(self, message="Hello World!"):
        self.message = message

    def extract_message(self, event_data):
        self.message = event_data.kwargs['message']

    def on_enter_E(self, msg=None):
        self.message = "I am E!" if msg is None else msg

    def on_exit_E(self):
        self.exit_message = "E go home..."

    def on_enter_F(self):
        self.message = "I am F!"

    @property
    def property_that_fails(self):
        return self.is_false


class InheritedStuff(Machine):

    def __init__(self, states, initial='A'):

        self.state = None

        Machine.__init__(self, states=states, initial=initial)

    @staticmethod
    def this_passes():
        return True


class DummyModel(object):
    pass


class SomeContext(object):
    def __init__(self, event_list):
        self._event_list = event_list

    def __enter__(self):
        self._event_list.append((self, "enter"))

    def __exit__(self, type, value, traceback):
        self._event_list.append((self, "exit"))


class _ungroup:
    """
    A sync+async context manager that unwraps single-element
    exception groups.
    """

    def __call__(self):
        "Singleton. Returns itself."
        return self

    @staticmethod
    def one(e):
        "convert the exceptiongroup @e to a single exception"
        if not isinstance(e, BaseExceptionGroup):
            return e

        try:
            Cancel = get_cancelled_exc_class()
        except AsyncLibraryNotFoundError:
            pass
        else:
            c, e = e.split(Cancel)
            if not e:
                e = c

        while isinstance(e, BaseExceptionGroup):
            if len(e.exceptions) != 1:
                break
            e = e.exceptions[0]
        return e

    def __enter__(self):
        return self

    async def __aenter__(self):
        return self

    def __exit__(self, c, e, t):
        if e is None:
            return
        e = self.one(e)
        raise e from None

    async def __aexit__(self, c, e, t):
        return self.__exit__(c, e, t)


ungroup = _ungroup()
