"""Top-level ECM sync facade; entry point for all synchronous DMS and security operations."""
from typing import TYPE_CHECKING, Any

from ecmind_blue_client.ecm._ecm import ECMAbstract
from ecmind_blue_client.ecm._ecm_exception import raise_for_blue_exception
from ecmind_blue_client.ecm.synchron._ecm_db_sync import ECMDbSync
from ecmind_blue_client.ecm.synchron._ecm_dms_sync import ECMDmsSync
from ecmind_blue_client.ecm.synchron._ecm_security_sync import ECMSecuritySync
from ecmind_blue_client.ecm.synchron._ecm_system_sync import ECMSystemSync
from ecmind_blue_client.pool import SyncPoolClient
from ecmind_blue_client.rpc._blue_exception import BlueException

if TYPE_CHECKING:
    from ecmind_blue_client import Jobs


class ECMSync(ECMAbstract[SyncPoolClient]):
    """Synchronous high-level ECM API.

    Provides access to folder, register, and document operations via ``ecm.dms``
    and server-level metadata via ``ecm.system``.
    All operations are blocking and intended for use in non-async code paths.
    """

    def __init__(self, client: SyncPoolClient) -> None:
        """Initialise the ECM instance with a pool client.

        Args:
            client: The pool client used to communicate with the ECMind Blue server.
        """
        super().__init__(client)
        self.dms: ECMDmsSync = ECMDmsSync(self)  # type: ignore[arg-type]
        self.security: ECMSecuritySync = ECMSecuritySync(self)  # type: ignore[arg-type]
        self.system: ECMSystemSync = ECMSystemSync(self)  # type: ignore[arg-type]
        self.db: ECMDbSync = ECMDbSync(self)  # type: ignore[arg-type]

    def impersonate(self, username: str) -> "ECMSync":
        """Return a user-scoped ``ECMSync`` instance, usable directly or as a context manager.

        Creates a new ``ECMSync`` bound to the same client that injects the
        ``$$$SwitchContextUserName$$$`` parameter into every server request.
        The returned instance supports ``with`` blocks (via ``__enter__`` / ``__exit__``)
        but can equally be used as a plain object without a ``with`` statement — just
        like :func:`open`.

        Args:
            username: The ECMind Blue username to impersonate.

        Returns:
            A new ``ECMSync`` instance with the user context set to ``username``.

        Example:
            ::

                # as context manager
                with ecm.impersonate("john") as ecm_john:
                    folder = ecm_john.dms.insert_and_get(MyFolder(Name="Test"))

                # direct usage
                ecm_john = ecm.impersonate("john")
                folder = ecm_john.dms.insert_and_get(MyFolder(Name="Test"))
        """
        instance = ECMSync(self._client)
        instance._impersonate_username = username  # pylint: disable=protected-access
        return instance

    def __enter__(self) -> "ECMSync":
        return self

    def __exit__(self, exc_type, exc_value, traceback) -> None:
        pass

    def execute(self, job: "Jobs", **kwargs: Any) -> Any:
        """Execute a job on the underlying client, passing kwargs through ``_inject_params``.

        Args:
            job: The ECM job identifier.
            **kwargs: Job parameters forwarded to ``client.execute`` after injection.

        Returns:
            The raw result returned by ``client.execute``.
        """
        try:
            return self._client.execute(job, **self._inject_params(kwargs))
        except BlueException as exc:
            raise_for_blue_exception(exc)
            raise
