"""Authentication backend that skips the email prompt on SSO sign-up."""

import logging
from typing import TYPE_CHECKING, override

from allianceauth.authentication.backends import StateBackend
from allianceauth.authentication.models import CharacterOwnership
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractBaseUser
from django.db import transaction

from aa_skip_email.helpers import make_placeholder_email

if TYPE_CHECKING:
    from esi.models import Token

logger = logging.getLogger(__name__)
User = get_user_model()


class SkipEmailBackend(StateBackend):
    """
    Drop-in replacement for AA's ``StateBackend`` that auto-fills email.

    On EVE SSO registration the user is created with a placeholder
    address generated by :func:`aa_skip_email.helpers.make_placeholder_email`
    instead of being prompted for a real email. Wire this backend into
    ``AUTHENTICATION_BACKENDS`` *in place of* AA's default backend.
    """

    @override
    @transaction.atomic
    def create_user(self, token: "Token") -> AbstractBaseUser:
        """
        Create a user from an EVE SSO token, atomically.

        Wraps the user / character-ownership / profile saves in a single
        transaction so a failure in ``CharacterOwnership.create_by_token``
        does not leave a half-registered user (placeholder email but no
        main_character) in the database.

        AA's ``User.post_save`` and ``UserProfile.post_save`` handlers
        run inside this transaction. If a downstream signal handler
        dispatches a Celery task, that handler is responsible for
        wrapping ``task.delay(...)`` in ``transaction.on_commit`` —
        otherwise the worker may pick up the task before the row is
        visible.
        """
        username = self.iterate_username(token.character_name)
        user = User.objects.create_user(username, is_active=True)
        user.set_unusable_password()
        user.email = make_placeholder_email(username, user.pk)
        user.save()
        token.user = user
        co = CharacterOwnership.objects.create_by_token(token)
        user.profile.main_character = co.character
        user.profile.save()
        logger.debug("Created new user %s", user)
        return user
