"""
Alta y baja de la sesión, colgadas de las señales de autenticación.

Van por señal y no dentro de la vista de ingreso a propósito: a
`django.contrib.auth.login` lo llaman también el panel interno, la suite con
`force_login` y cualquier flujo que se agregue mañana. Anotarlo en la vista
dejaría todas esas puertas sin registrar, y una pantalla de sesiones que muestra
menos de las que hay falla justo en lo único para lo que existe.
"""

from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.dispatch import receiver

from apps.accounts.models import Session
from apps.accounts.services import record_session, revoke_session_record
from apps.core.requests import client_ip, user_agent


@receiver(user_logged_in)
def on_user_logged_in(sender, request, user, **kwargs):
    if request is None:
        return

    # `login()` vacía la sesión cuando la cookie traía la de otra cuenta, y en
    # ese camino todavía no hay clave asignada. Se fuerza el alta acá porque sin
    # clave no hay a qué referirse y la sesión quedaría sin anotar.
    if request.session.session_key is None:
        request.session.save()

    record_session(
        user,
        session_key=request.session.session_key,
        ip_address=client_ip(request),
        user_agent=user_agent(request, Session.USER_AGENT_MAX_LENGTH),
    )


@receiver(user_logged_out)
def on_user_logged_out(sender, request, user, **kwargs):
    # La señal se emite antes de que `logout()` vacíe la sesión, así que la
    # clave todavía está disponible. Después ya no habría forma de saber qué
    # fila dar de baja.
    if request is None or not request.session.session_key:
        return

    revoke_session_record(request.session.session_key)
