"""
Single source of truth for placeholder-email generation.

The SSO backend, the Celery task and the management command all defer
to :func:`make_placeholder_email` so that a given (username, user_id)
pair always yields the same address regardless of which entry point
filled it in.
"""

from __future__ import annotations

import re
import uuid
from typing import TYPE_CHECKING, Final

from aa_skip_email.app_settings import (
    AA_SKIP_EMAIL_DOMAIN,
    AA_SKIP_EMAIL_FALLBACK_USERNAME,
    AA_SKIP_EMAIL_SEPARATOR,
)

if TYPE_CHECKING:
    from django.contrib.auth.models import AbstractBaseUser
    from django.db.models import QuerySet

# RFC 5321 caps the local-part of an email address at 64 octets.
_LOCAL_PART_MAX_LEN: Final[int] = 64

# Pre-compiled at import to avoid re-compiling per call: the helper is
# invoked from a tight loop (Celery task / management command) over
# thousands of users.
_UNSAFE_CHARS_RE: Final[re.Pattern[str]] = re.compile(r"[^A-Za-z0-9.+-]+")


def is_placeholder_email(email: str | None) -> bool:
    """
    Return True if ``email`` was produced by this plugin.

    The check is purely string-based and matches the configured
    ``AA_SKIP_EMAIL_DOMAIN`` case-insensitively (RFC 5321 declares the
    domain part case-insensitive). Falsy values (``None`` / empty
    string) always return False.

    Use this anywhere you need to distinguish a generated placeholder
    from a real address: management command filters, downstream
    consumers (OIDC ``email_verified`` claim, admin templates, etc.).
    Centralising the check keeps every call site aligned with the
    format produced by :func:`make_placeholder_email`.
    """
    if not email:
        return False
    return email.lower().endswith(f"@{AA_SKIP_EMAIL_DOMAIN.lower()}")


def make_placeholder_email(
    username: str | None = None, user_id: int | None = None
) -> str:
    """
    Build a deterministic placeholder address for a user.

    Sanitizes ``username`` to a conservative character class, glues a
    suffix (``user_id`` if given, otherwise a fresh UUID hex), and
    appends ``@AA_SKIP_EMAIL_DOMAIN``. The local-part is capped at
    64 octets per RFC 5321.

    Falsy ``username`` (None or empty) and usernames that sanitize to
    an empty string both fall back to ``AA_SKIP_EMAIL_FALLBACK_USERNAME``.
    """
    if username:
        safe = (
            _UNSAFE_CHARS_RE.sub(AA_SKIP_EMAIL_SEPARATOR, username).strip(
                AA_SKIP_EMAIL_SEPARATOR
            )
            or AA_SKIP_EMAIL_FALLBACK_USERNAME
        )
    else:
        safe = AA_SKIP_EMAIL_FALLBACK_USERNAME
    suffix = str(user_id) if user_id is not None else uuid.uuid4().hex
    separator = AA_SKIP_EMAIL_SEPARATOR
    max_safe = max(1, _LOCAL_PART_MAX_LEN - len(separator) - len(suffix))
    safe = safe[:max_safe]
    return f"{safe}{separator}{suffix}@{AA_SKIP_EMAIL_DOMAIN}"


def get_placeholder_users() -> QuerySet[AbstractBaseUser]:
    """
    Return a queryset of users whose ``email`` is a plugin placeholder.

    The ORM-side analogue of :func:`is_placeholder_email`. Use this in
    admin filters, audit reports, or anywhere a queryset is needed —
    keeps the placeholder-detection predicate in one place.

    Lazy-imports the User model so this module stays importable without
    a configured Django ``settings`` (helpful for type-checkers).
    """
    from django.contrib.auth import get_user_model

    return get_user_model().objects.filter(
        email__iendswith=f"@{AA_SKIP_EMAIL_DOMAIN}"
    )
