"""Small credential-plane interface consumed by execution bindings."""

from datetime import UTC, datetime, timedelta

from src.config import get_settings
from src.core.exceptions import ValidationError
from src.core.security.encryption import decrypt_value, encrypt_value
from src.domain.provider_auth.manifests import (
    CONNECTOR_FAMILIES,
    FAMILY_SCOPES,
    HUBSPOT_CONNECTOR_FAMILIES,
    HUBSPOT_FAMILY_SCOPES,
    MICROSOFT_ADS_CONNECTOR_FAMILIES,
    MICROSOFT_ADS_FAMILY_SCOPES,
    SALESFORCE_CONNECTOR_FAMILIES,
    SALESFORCE_FAMILY_SCOPES,
    X_ADS_CONNECTOR_FAMILIES,
    X_ADS_FAMILY_SCOPES,
)
from src.domain.provider_auth.repository import ProviderAuthRepository
from src.integrations.google_oauth import GoogleOAuthClient, GoogleOAuthError
from src.integrations.hubspot_oauth import HubSpotOAuthClient, HubSpotOAuthError
from src.integrations.microsoft_ads_oauth import (
    MicrosoftAdsOAuthClient,
    MicrosoftAdsOAuthError,
)
from src.integrations.salesforce_oauth import SalesforceOAuthClient, SalesforceOAuthError
from src.integrations.x_ads_oauth import XAdsOAuthClient, XAdsOAuthError


async def execution_credentials(db, *, workspace_id, project_id, connection_id, connector_key):
    """Return short-lived access only. Platform refresh/client secrets never leave Core."""
    row = await ProviderAuthRepository(db).connection(workspace_id, project_id, connection_id)
    if not row or row.actor_type != "project" or row.actor_id != str(project_id):
        raise ValidationError("Provider connection is not available for this project")
    provider_maps = {
        "google": (CONNECTOR_FAMILIES, FAMILY_SCOPES, GoogleOAuthClient, GoogleOAuthError),
        "hubspot": (
            HUBSPOT_CONNECTOR_FAMILIES,
            HUBSPOT_FAMILY_SCOPES,
            HubSpotOAuthClient,
            HubSpotOAuthError,
        ),
        "salesforce": (
            SALESFORCE_CONNECTOR_FAMILIES,
            SALESFORCE_FAMILY_SCOPES,
            SalesforceOAuthClient,
            SalesforceOAuthError,
        ),
        "x_ads": (
            X_ADS_CONNECTOR_FAMILIES,
            X_ADS_FAMILY_SCOPES,
            XAdsOAuthClient,
            XAdsOAuthError,
        ),
        "microsoft_ads": (
            MICROSOFT_ADS_CONNECTOR_FAMILIES,
            MICROSOFT_ADS_FAMILY_SCOPES,
            MicrosoftAdsOAuthClient,
            MicrosoftAdsOAuthError,
        ),
    }
    connector_map, family_scopes, client_cls, error_cls = provider_maps.get(
        row.provider, (None, None, None, None)
    )
    family = connector_map.get(connector_key) if connector_map else None
    if not family or not set(family_scopes[family]) <= set(row.effective_scopes):
        raise ValidationError("scope_escalation_pending")
    if row.status != "active":
        raise ValidationError("reauthentication_required")
    now = datetime.now(UTC)
    if not row.expires_at or row.expires_at <= now + timedelta(minutes=2):
        if not row.secrets_enc.get("refresh_token"):
            raise ValidationError("reauthentication_required")
        cfg = get_settings()
        prefix = f"{row.provider}_platform_"
        try:
            token_data = {
                "grant_type": "refresh_token",
                "refresh_token": decrypt_value(row.secrets_enc["refresh_token"]),
                "client_id": getattr(cfg, prefix + "client_id"),
                "client_secret": getattr(cfg, prefix + "client_secret"),
            }
            if row.provider == "salesforce":
                token_data["login_host"] = row.secrets_enc.get(
                    "login_host", "https://login.salesforce.com"
                )
            if row.provider == "microsoft_ads":
                token_data["scope"] = "https://ads.microsoft.com/msads.manage offline_access"
            token = await client_cls().token(**token_data)
        except error_cls as exc:
            if exc.code == "invalid_grant":
                row.status = "reauthentication_required"
                await db.commit()
            raise ValidationError(
                "reauthentication_required"
                if exc.code == "invalid_grant"
                else "provider_unavailable"
            ) from None
        row.secrets_enc = {**row.secrets_enc, "access_token": encrypt_value(token["access_token"])}
        row.expires_at = now + timedelta(seconds=int(token.get("expires_in", 0)))
        await db.flush()
    credentials = {"access_token": decrypt_value(row.secrets_enc["access_token"])}
    if row.provider == "salesforce" and row.secrets_enc.get("instance_url"):
        credentials["instance_url"] = decrypt_value(row.secrets_enc["instance_url"])
    if row.provider == "hubspot" and row.secrets_enc.get("portal_id"):
        credentials["portal_id"] = decrypt_value(row.secrets_enc["portal_id"])
    return credentials, list(row.effective_scopes)
