# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Security service for token management operations.
Provides centralized access to token refresh and management functionality.
"""

import logging
from typing import Optional, Callable

from modules.datamodels.datamodelSecurity import Token
from modules.auth import TokenManager

logger = logging.getLogger(__name__)


class SecurityService:
    """Security service providing token management operations."""
    
    def __init__(self, services):
        """Initialize security service with service center access.
        
        Args:
            services: Service center instance providing access to interfaces
        """
        self.services = services
        self._tokenManager = TokenManager()
    
    def getFreshToken(self, connectionId: str, secondsBeforeExpiry: int = 30 * 60) -> Optional[Token]:
        """Get a fresh token for a connection, refreshing when expiring soon.
        
        Reads the latest stored token via interface layer, then
        uses ensureFreshToken to refresh if needed and persists the refreshed
        token via interface layer.
        
        Args:
            connectionId: ID of the connection to get token for
            secondsBeforeExpiry: Threshold window to proactively refresh (default: 30 minutes)
            
        Returns:
            Token object or None if not found/expired
        """
        try:
            # Use interface from services instead of getRootInterface()
            interfaceDbApp = self.services.interfaceDbApp
            
            token = interfaceDbApp.getConnectionToken(connectionId)
            if not token:
                return None
            
            return self._tokenManager.ensureFreshToken(
                token,
                secondsBeforeExpiry=secondsBeforeExpiry,
                saveCallback=lambda t: interfaceDbApp.saveConnectionToken(t)
            )
        except Exception as e:
            logger.error(f"getFreshToken: Error fetching or refreshing token for connection {connectionId}: {e}")
            return None
    
    def refreshToken(self, oldToken: Token) -> Optional[Token]:
        """Refresh an expired token using the appropriate OAuth service.
        
        Args:
            oldToken: Token object to refresh
            
        Returns:
            Refreshed Token object or None if refresh failed
        """
        try:
            return self._tokenManager.refreshToken(oldToken)
        except Exception as e:
            logger.error(f"refreshToken: Error refreshing token: {e}")
            return None
    
    def ensureFreshToken(self, token: Token, *, secondsBeforeExpiry: int = 30 * 60, 
                        saveCallback: Optional[Callable[[Token], None]] = None) -> Optional[Token]:
        """Ensure a token is fresh; refresh if expiring within threshold.
        
        Args:
            token: Existing token to validate/refresh
            secondsBeforeExpiry: Threshold window to proactively refresh (default: 30 minutes)
            saveCallback: Optional function to persist a refreshed token
            
        Returns:
            A fresh token (refreshed or original) or None if refresh failed
        """
        try:
            return self._tokenManager.ensureFreshToken(
                token,
                secondsBeforeExpiry=secondsBeforeExpiry,
                saveCallback=saveCallback
            )
        except Exception as e:
            logger.error(f"ensureFreshToken: Error ensuring fresh token: {e}")
            return None
    
    def refreshMicrosoftToken(self, refreshToken: str, userId: str, oldToken: Token) -> Optional[Token]:
        """Refresh Microsoft OAuth token using refresh token.
        
        Args:
            refreshToken: Microsoft refresh token
            userId: User ID owning the token
            oldToken: Previous token object to preserve connection ID
            
        Returns:
            New Token object or None if refresh failed
        """
        try:
            return self._tokenManager.refreshMicrosoftToken(refreshToken, userId, oldToken)
        except Exception as e:
            logger.error(f"refreshMicrosoftToken: Error refreshing Microsoft token: {e}")
            return None
    
    def refreshGoogleToken(self, refreshToken: str, userId: str, oldToken: Token) -> Optional[Token]:
        """Refresh Google OAuth token using refresh token.
        
        Args:
            refreshToken: Google refresh token
            userId: User ID owning the token
            oldToken: Previous token object to preserve connection ID
            
        Returns:
            New Token object or None if refresh failed
        """
        try:
            return self._tokenManager.refreshGoogleToken(refreshToken, userId, oldToken)
        except Exception as e:
            logger.error(f"refreshGoogleToken: Error refreshing Google token: {e}")
            return None

