# Copyright (c) 2025 Patrick Motsch
# All rights reserved.

"""
API Client helper for SharePoint operations.
Handles Microsoft Graph API calls with timeout and error handling.
"""

import logging
import aiohttp
import asyncio
from typing import Dict, Any

logger = logging.getLogger(__name__)

class ApiClientHelper:
    """Helper for Microsoft Graph API calls"""
    
    def __init__(self, methodInstance):
        self.method = methodInstance
        self.services = methodInstance.services
        self._session: aiohttp.ClientSession = None
    
    async def _getSession(self) -> aiohttp.ClientSession:
        if self._session is None or self._session.closed:
            timeout = aiohttp.ClientTimeout(total=30)
            self._session = aiohttp.ClientSession(timeout=timeout)
        return self._session
    
    async def close(self):
        if self._session and not self._session.closed:
            await self._session.close()
            self._session = None
    
    async def makeGraphApiCall(self, endpoint: str, method: str = "GET", data: bytes = None) -> Dict[str, Any]:
        """
        Make a Microsoft Graph API call with timeout and detailed logging.
        
        Args:
            endpoint: API endpoint (without base URL)
            method: HTTP method (GET, POST, PUT)
            data: Optional request body data (bytes)
            
        Returns:
            Dict with API response or error information
        """
        try:
            sp = getattr(self.services, 'sharepoint', None)
            if not sp:
                return {"error": "SharePoint service not configured with access token"}
            # Service center: accessToken on service directly. Legacy: wrapped in PublicService._target
            try:
                access_token = getattr(sp, 'accessToken', None)
                if access_token is None:
                    target = getattr(sp, '_target', None)  # Only legacy hub has _target
                    if target is not None:
                        access_token = getattr(target, 'accessToken', None)
            except AttributeError as ae:
                logger.warning(f"SharePoint token extraction failed: {ae}")
                return {"error": "SharePoint service not configured with access token"}
            if not access_token:
                return {"error": "SharePoint service not configured with access token"}

            headers = {
                "Authorization": f"Bearer {access_token}",
                "Content-Type": "application/json" if data and method != "PUT" else "application/octet-stream" if data else "application/json"
            }
            
            url = f"https://graph.microsoft.com/v1.0/{endpoint}"
            logger.info(f"Making Graph API call: {method} {url}")
            
            session = await self._getSession()
            
            successCodes = {"GET": [200], "PUT": [200, 201], "POST": [200, 201], "DELETE": [200, 204]}
            httpMethod = getattr(session, method.lower(), None)
            if not httpMethod:
                return {"error": f"Unsupported HTTP method: {method}"}
            
            kwargs = {"headers": headers}
            if data is not None:
                kwargs["data"] = data
            
            async with httpMethod(url, **kwargs) as response:
                logger.info(f"Graph API response: {response.status}")
                if response.status in successCodes.get(method, [200]):
                    if method == "DELETE":
                        return {"success": True}
                    result = await response.json()
                    return result
                else:
                    errorText = await response.text()
                    logger.error(f"Graph API call failed: {response.status} - {errorText}")
                    return {"error": f"API call failed: {response.status} - {errorText}"}
                            
        except asyncio.TimeoutError:
            logger.error(f"Graph API call timed out after 30 seconds: {endpoint}")
            return {"error": f"API call timed out after 30 seconds: {endpoint}"}
        except Exception as e:
            logger.error(f"Error making Graph API call: {str(e)}")
            return {"error": f"Error making Graph API call: {str(e)}"}

