# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""ConnectorResolver -- resolves a connectionId to the correct ProviderConnector and ServiceAdapter.

Registry maps authority values to ProviderConnector classes.
The resolver loads the UserConnection, obtains a fresh token via SecurityService,
and instantiates the appropriate connector.
"""

import logging
from typing import Dict, Any, Type, Optional

from modules.connectors.connectorProviderBase import ProviderConnector, ServiceAdapter

logger = logging.getLogger(__name__)


class ConnectorResolver:
    """Resolves connectionId → ProviderConnector (with fresh token) → ServiceAdapter."""

    _providerRegistry: Dict[str, Type[ProviderConnector]] = {}

    def __init__(self, securityService, dbInterface):
        """
        Args:
            securityService: SecurityService instance (for getFreshToken)
            dbInterface: DB interface with getUserConnection(connectionId)
        """
        self._security = securityService
        self._db = dbInterface
        self._ensureRegistered()

    def _ensureRegistered(self):
        """Lazy-register known providers on first instantiation."""
        if ConnectorResolver._providerRegistry:
            return
        try:
            from modules.connectors.providerMsft.connectorMsft import MsftConnector
            ConnectorResolver._providerRegistry["msft"] = MsftConnector
        except ImportError:
            logger.warning("MsftConnector not available")

        try:
            from modules.connectors.providerGoogle.connectorGoogle import GoogleConnector
            ConnectorResolver._providerRegistry["google"] = GoogleConnector
        except ImportError:
            logger.debug("GoogleConnector not available (stub)")

        try:
            from modules.connectors.providerFtp.connectorFtp import FtpConnector
            ConnectorResolver._providerRegistry["local:ftp"] = FtpConnector
        except ImportError:
            logger.debug("FtpConnector not available (stub)")

        try:
            from modules.connectors.providerClickup.connectorClickup import ClickupConnector
            ConnectorResolver._providerRegistry["clickup"] = ClickupConnector
        except ImportError:
            logger.warning("ClickupConnector not available")

    async def resolve(self, connectionId: str) -> ProviderConnector:
        """Resolve connectionId to a ProviderConnector with a fresh access token."""
        connection = await self._loadConnection(connectionId)
        if not connection:
            raise ValueError(f"UserConnection not found: {connectionId}")

        authority = getattr(connection, "authority", None)
        if not authority:
            raise ValueError(f"Connection {connectionId} has no authority")

        authorityStr = authority.value if hasattr(authority, "value") else str(authority)
        providerClass = self._providerRegistry.get(authorityStr)
        if not providerClass:
            raise ValueError(f"No ProviderConnector registered for authority: {authorityStr}")

        token = self._security.getFreshToken(connectionId)
        if not token or not token.tokenAccess:
            raise ValueError(f"No valid token for connection {connectionId}")

        return providerClass(connection, token.tokenAccess)

    async def resolveService(self, connectionId: str, service: str) -> ServiceAdapter:
        """Resolve connectionId + service name to a concrete ServiceAdapter."""
        provider = await self.resolve(connectionId)
        available = provider.getAvailableServices()
        if service not in available:
            raise ValueError(f"Service '{service}' not available. Options: {available}")
        return provider.getServiceAdapter(service)

    async def _loadConnection(self, connectionId: str) -> Optional[Any]:
        """Load UserConnection from DB."""
        try:
            if hasattr(self._db, "getUserConnection"):
                return self._db.getUserConnection(connectionId)
            if hasattr(self._db, "loadRecord"):
                from modules.datamodels.datamodelUam import UserConnection
                return self._db.loadRecord(UserConnection, connectionId)
        except Exception as e:
            logger.error(f"Failed to load connection {connectionId}: {e}")
        return None
