"""OIDC claims for the IILMP identity provider.

IILMP acts as the OAuth2/OpenID-Connect provider so Moodle's built-in OAuth2 auth
plugin can offer "Log in with IILMP". Moodle matches/creates its ``mdl_user`` by
the ``email`` claim, so we expose email + name claims sourced from ``CustomUser``
and its ``UserProfile``.

Wired via ``OAUTH2_PROVIDER["OAUTH2_VALIDATOR_CLASS"]`` in settings.
"""
from __future__ import annotations

import logging

from oauth2_provider.oauth2_validators import OAuth2Validator

logger = logging.getLogger(__name__)


def _schedule_role_sync(user) -> None:
    """Queue the Moodle role projection for a mapped user after SSO.

    Countdown gives Moodle time to commit the new ``mdl_user`` on first login
    (the task retries on not-found anyway). Best-effort: a down broker must
    never break the SSO exchange itself.
    """
    from apps.core.authentication.moodle_roles import desired_moodle_role

    if desired_moodle_role(user) is None:
        return
    try:
        from apps.core.tasks import sync_moodle_role

        sync_moodle_role.apply_async(args=[user.pk], countdown=20)
    except Exception:  # pragma: no cover — broker down; SSO must proceed
        logger.warning("could not queue Moodle role sync for %s", user.pk, exc_info=True)


class IILMPOAuth2Validator(OAuth2Validator):
    # Map OIDC scopes to the claim names we emit for that scope.
    oidc_claim_scope = OAuth2Validator.oidc_claim_scope
    oidc_claim_scope.update(
        {
            "email": "email",
            "email_verified": "email",
            "given_name": "profile",
            "family_name": "profile",
            "name": "profile",
        }
    )

    def get_additional_claims(self, request):
        user = request.user
        full_name = (user.get_full_name() or "").strip()
        _schedule_role_sync(user)
        return {
            "email": user.email,
            "email_verified": bool(getattr(user, "email_verified", False)),
            "given_name": getattr(user, "first_name", "") or "",
            "family_name": getattr(user, "last_name", "") or "",
            "name": full_name or user.email,
        }
