"""
Microsoft Graph API Client — shared by Copilot, Purview, Viva, SharePoint sync services.

Uses OAuth2 client_credentials flow (app-only, no user interaction).
Single Azure AD App Registration covers all Graph data sources.
"""

from datetime import datetime, timezone

import httpx

from app.config import get_settings


class GraphClient:
    """Async Microsoft Graph API client with automatic token management."""

    TOKEN_URL = "https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"
    GRAPH_BASE = "https://graph.microsoft.com"

    def __init__(self):
        settings = get_settings()
        self.tenant_id = settings.graph_tenant_id
        self.client_id = settings.graph_client_id
        self.client_secret = settings.graph_client_secret
        self._token: str | None = None
        self._token_expiry: datetime | None = None
        self._http = httpx.AsyncClient(timeout=30.0)

    @property
    def is_configured(self) -> bool:
        return all([self.tenant_id, self.client_id, self.client_secret])

    async def _ensure_token(self):
        """Get or refresh OAuth2 access token."""
        now = datetime.now(timezone.utc)
        if self._token and self._token_expiry and now < self._token_expiry:
            return

        url = self.TOKEN_URL.format(tenant_id=self.tenant_id)
        data = {
            "client_id": self.client_id,
            "client_secret": self.client_secret,
            "scope": "https://graph.microsoft.com/.default",
            "grant_type": "client_credentials",
        }

        resp = await self._http.post(url, data=data)
        resp.raise_for_status()
        token_data = resp.json()

        self._token = token_data["access_token"]
        expires_in = token_data.get("expires_in", 3600)
        from datetime import timedelta
        self._token_expiry = now + timedelta(seconds=expires_in - 60)

    async def get(self, endpoint: str, params: dict | None = None, api_version: str = "v1.0") -> dict:
        """Authenticated GET request to Graph API."""
        await self._ensure_token()
        url = f"{self.GRAPH_BASE}/{api_version}/{endpoint.lstrip('/')}"
        resp = await self._http.get(
            url,
            params=params,
            headers={"Authorization": f"Bearer {self._token}"},
        )
        resp.raise_for_status()
        return resp.json()

    async def post(self, endpoint: str, body: dict, api_version: str = "v1.0") -> dict:
        """Authenticated POST request to Graph API."""
        await self._ensure_token()
        url = f"{self.GRAPH_BASE}/{api_version}/{endpoint.lstrip('/')}"
        resp = await self._http.post(
            url,
            json=body,
            headers={"Authorization": f"Bearer {self._token}"},
        )
        resp.raise_for_status()
        return resp.json()

    async def close(self):
        await self._http.aclose()
