# Copyright 2025 Softwell S.r.l.
# Licensed under the Apache License, Version 2.0

"""Server-managed session with metadata, Bag data, and auth context.

A Session groups request-scoped state under a unique ID with expiry tracking.
SessionMiddleware creates or reconnects sessions via cookies and attaches
them to ``scope["session"]``. Each session holds an Avatar for the
authenticated user and a Bag for arbitrary application data.
"""

from __future__ import annotations

import time
from typing import Any

from genro_bag import Bag

from .avatar import Avatar

__all__ = ["Session"]


class Session:
    """Server-managed session with meta, data (Bag), and auth snapshot.

    Attributes:
        _id: Unique session token.
        _meta: Server-managed metadata (created_at, last_access, ttl).
        _data: Application data as Bag.
        _auth: Auth snapshot from session creation.
    """

    __slots__ = ("_id", "_meta", "_data", "_auth", "_avatar")

    def __init__(self, session_id: str, auth: dict[str, Any] | None, ttl: int) -> None:
        """Initialize session.

        Args:
            session_id: Unique session token.
            auth: Auth dict snapshot from authentication, or None.
            ttl: Time-to-live in seconds.
        """
        now = time.time()
        self._id = session_id
        self._meta: dict[str, Any] = {
            "created_at": now,
            "last_access": now,
            "ttl": ttl,
        }
        self._data = Bag()
        self._auth = auth
        self._avatar = Avatar(auth=auth)

    @property
    def id(self) -> str:
        """Unique session token."""
        return self._id

    @property
    def meta(self) -> dict[str, Any]:
        """Server-managed metadata: created_at, last_access, ttl."""
        return self._meta

    @property
    def data(self) -> Bag:
        """Application data as Bag."""
        return self._data

    @property
    def auth(self) -> dict[str, Any] | None:
        """Auth snapshot from session creation."""
        return self._auth

    @property
    def avatar(self) -> Avatar:
        """User identity avatar built from auth snapshot."""
        return self._avatar

    def touch(self) -> None:
        """Update last_access timestamp."""
        self._meta["last_access"] = time.time()

    def is_expired(self) -> bool:
        """Check if session has exceeded its TTL."""
        ttl: int = self._meta["ttl"]
        if ttl <= 0:
            return True
        last_access: float = self._meta["last_access"]
        return bool((time.time() - last_access) > ttl)


if __name__ == "__main__":
    pass
