import requests
from m365_user_manager.managers.environment_manager import EnvironmentManager
from m365_user_manager.exceptions.exceptions import TokenManagerError

class TokenManager:
    """
    Handles authentication token acquisition and management for Microsoft Graph API.
    
    Manages the retrieval and caching of OAuth2 access tokens required for
    Microsoft Graph API operations.
    
    Usage:
        token_manager = TokenManager()
        token = token_manager.get_access_token(
            client_id="your_id",
            client_secret="your_secret",
            tenant_id="your_tenant"
        )
        
    Methods:
        get_access_token(): Retrieves valid access token with required permissions
    
    Raises:
        TokenManagerError: When token acquisition fails
    """
    def __init__(self, discord_webhook_url: str = None):
        self.discord_webhook_url = discord_webhook_url
        self.logger = EnvironmentManager(discord_webhook_url=self.discord_webhook_url).setup_logging()

    def get_access_token(self, client_id: str, client_secret: str, tenant_id: str) -> str:
        """
        Get Microsoft Graph API access token with required permissions.
        
        Args:
            client_id (str): Azure AD application client ID
            client_secret (str): Azure AD application client secret
            tenant_id (str): Azure AD tenant ID
            
        Returns:
            str: Valid access token for Microsoft Graph API
            
        Raises:
            TokenManagerError: When authentication fails or credentials are invalid
        """
        # Validate individual parameters for specific error messages
        if not client_id:
            raise TokenManagerError(
                "Missing client_id in authentication credentials",
                status_code=400
            )
        if not client_secret:
            raise TokenManagerError(
                "Missing client_secret in authentication credentials",
                status_code=400
            )
        if not tenant_id:
            raise TokenManagerError(
                "Missing tenant_id in authentication credentials",
                status_code=400
            )
            
        token_url = f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"
        token_data = {
            "grant_type": "client_credentials",
            "client_id": client_id,
            "client_secret": client_secret,
            "scope": "https://graph.microsoft.com/.default"
        }
        
        try:
            response = requests.post(token_url, data=token_data, timeout=30)
            
            if response.status_code == 401:
                raise TokenManagerError(
                    "Invalid authentication credentials provided",
                    status_code=401
                )
                
            response.raise_for_status()
            token_data = response.json()
            
            if "access_token" not in token_data:
                raise TokenManagerError(
                    "Invalid response: No access token returned",
                    status_code=response.status_code
                )
                
            return token_data["access_token"]
            
        except requests.exceptions.Timeout:
            self.logger.error("Token request timed out after 30 seconds")
            raise TokenManagerError(
                "Token request timed out after 30 seconds",
                status_code=408
            )
        except requests.exceptions.RequestException as e:
            self.logger.error(f"Failed to acquire access token: {str(e)}")
            raise TokenManagerError(
                f"Token acquisition failed: {str(e)}",
                status_code=getattr(e.response, 'status_code', 500)
            )