"""
Core model abstractions for session-based authentication.

This module defines the database schema for persistent authentication sessions.
It supports multiple transport layers, rotating credentials, and stateful
revocation, with optimized indexes for high-concurrency environments.
"""

from django.db import models
from django.conf import settings
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from drf_sessions.contexts import ContextParams
from drf_sessions.choices import AUTH_TRANSPORT
from drf_sessions.managers import SessionManager
from drf_sessions.validators import validate_context
from drf_sessions.utils.generators import generate_session_id


class BaseModel(models.Model):
    """
    Base abstraction providing creation timestamps and default ordering.
    """

    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        abstract = True
        ordering = ["-created_at"]


class AbstractSession(BaseModel):
    """
    A stateful container representing a user's authenticated connection.

    Stores metadata about the connection source (transport, user agent, IP)
    and manages the lifecycle of the session through absolute expiry and
    explicit revocation timestamps.
    """

    session_id = models.UUIDField(
        default=generate_session_id, unique=True, editable=False
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="+"
    )

    transport = models.CharField(max_length=6, choices=AUTH_TRANSPORT.choices)
    context = models.JSONField(default=dict, blank=True, validators=[validate_context])

    revoked_at = models.DateTimeField(null=True, blank=True)
    last_activity_at = models.DateTimeField(default=timezone.now)
    absolute_expiry = models.DateTimeField(null=True, blank=True, db_index=True)

    objects: SessionManager = SessionManager()

    class Meta(BaseModel.Meta):
        abstract = True
        verbose_name = _("Session")
        verbose_name_plural = _("Sessions")
        indexes = [
            models.Index(fields=["transport", "created_at"], name="session_audit_idx"),
            models.Index(
                fields=["user", "revoked_at", "created_at"], name="session_mgmt_idx"
            ),
            models.Index(
                fields=["session_id", "revoked_at", "absolute_expiry"],
                name="session_auth_composite_idx",
            ),
        ]

    def __str__(self) -> str:
        return f"{self.user.get_username()} ({self.session_id})"

    @property
    def context_obj(self) -> ContextParams:
        return ContextParams(self.context)

    def revoke(self, commit: bool = True) -> None:
        if self.revoked_at is None:
            self.revoked_at = timezone.now()
            if commit:
                self.save(update_fields=["revoked_at"])
