"""Salesforce OAuth adapter. Runtime instance URLs are returned by Salesforce."""

import httpx


class SalesforceOAuthError(Exception):
    def __init__(self, code="provider_unavailable"):
        self.code = code
        super().__init__(code)


class SalesforceOAuthClient:
    async def token(self, **data):
        login_host = data.pop("login_host", "https://login.salesforce.com").rstrip("/")
        async with httpx.AsyncClient(timeout=20) as client:
            try:
                response = await client.post(f"{login_host}/services/oauth2/token", data=data)
                payload = response.json()
            except (httpx.HTTPError, ValueError):
                raise SalesforceOAuthError() from None
        if response.is_error:
            code = payload.get("error")
            raise SalesforceOAuthError(
                code if code in {"invalid_grant", "invalid_client"} else "provider_unavailable"
            )
        if not payload.get("access_token"):
            raise SalesforceOAuthError()
        return payload

    async def userinfo(self, token):
        url = token.get("id")
        if not url:
            raise SalesforceOAuthError("identity_not_verified")
        async with httpx.AsyncClient(timeout=20) as client:
            try:
                response = await client.get(
                    url, headers={"Authorization": f"Bearer {token['access_token']}"}
                )
                response.raise_for_status()
                payload = response.json()
            except (httpx.HTTPError, ValueError):
                raise SalesforceOAuthError() from None
        if not payload.get("user_id"):
            raise SalesforceOAuthError("identity_not_verified")
        return {
            "sub": str(payload["user_id"]),
            "instance_url": token.get("instance_url", ""),
        }
