"""Extension to the :class:`SHVMethods` that provides dynamic methods addition."""

from __future__ import annotations

import collections.abc
import contextlib

from .methods import SHVMethods


class SHVDynamicMethods(SHVMethods):
    """SHV RPC methods and signals implementation helper with runtime addition.

    The implementation of :class:`SHVMethods` intentionally doesn't provide an
    easy way to add additional methods after they were initialized. The reason
    is simplicity of the implementation. On the other hand there are use cases
    when having this functionality is beneficial and for that reason this class
    provides more complex extension to that one.

    The primary use case is to ad-hoc register slim methods in the running
    application that can be later removed again. This is handy in mocking
    scenarios where we want to provide only methods needed for the given test
    or even overlay the existing implementation with some simpler one.
    """

    async def register(
        self, *methods: SHVMethods.Method, overlay: bool = False, notify: bool = True
    ) -> None:
        """Register the given methods all at once."""
        raise NotImplementedError

    async def unregister(self, *methods: SHVMethods.Method) -> None:
        """Revert :meth:`register`."""
        raise NotImplementedError

    @contextlib.asynccontextmanager
    async def temporary_methods(
        self, *methods: SHVMethods.Method, overlay: bool = False, notify: bool = True
    ) -> collections.abc.AsyncIterator[SHVDynamicMethods]:
        """Asynchronous context manager for temporary methods registration."""
        await self.register(*methods, overlay=overlay, notify=notify)
        try:
            yield self
        finally:
            await self.unregister(*methods)
