# Copyright 2025 Softwell S.r.l.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Tests for session store — MemorySessionStore and Session class."""

import time

from genro_bag import Bag

from genro_asgi.session import MemorySessionStore, Session


class TestSession:
    """Tests for Session class."""

    def test_session_meta(self) -> None:
        """Session has created_at, last_access, ttl in meta."""
        session = Session(session_id="test_id", auth=None, ttl=3600)

        assert session.meta["created_at"] > 0
        assert session.meta["last_access"] > 0
        assert session.meta["ttl"] == 3600

    def test_session_data_is_bag(self) -> None:
        """Session data is a Bag instance."""
        session = Session(session_id="test_id", auth=None, ttl=3600)

        assert isinstance(session.data, Bag)

    def test_session_touch_updates_last_access(self) -> None:
        """touch() updates last_access timestamp."""
        session = Session(session_id="test_id", auth=None, ttl=3600)
        first_access = session.meta["last_access"]

        time.sleep(0.01)
        session.touch()

        assert session.meta["last_access"] > first_access

    def test_session_expiry(self) -> None:
        """Session with ttl=0 is immediately expired."""
        session = Session(session_id="test_id", auth=None, ttl=0)

        assert session.is_expired()

    def test_session_auth_snapshot(self) -> None:
        """Session preserves auth dict from creation."""
        auth = {"identity": "admin", "tags": ["admin"], "backend": "bearer"}
        session = Session(session_id="test_id", auth=auth, ttl=3600)

        assert session.auth is auth
        assert session.auth["identity"] == "admin"


class TestMemorySessionStore:
    """Tests for MemorySessionStore."""

    def test_create_session(self) -> None:
        """store.create() returns Session with valid id."""
        store = MemorySessionStore()
        session = store.create()

        assert isinstance(session, Session)
        assert len(session.id) > 0

    def test_get_session(self) -> None:
        """store.get(id) returns the created session."""
        store = MemorySessionStore()
        session = store.create()
        retrieved = store.get(session.id)

        assert retrieved is session

    def test_get_nonexistent(self) -> None:
        """store.get() for unknown id returns None."""
        store = MemorySessionStore()

        assert store.get("nonexistent") is None

    def test_delete_session(self) -> None:
        """store.delete(id) removes session from store."""
        store = MemorySessionStore()
        session = store.create()
        session_id = session.id

        store.delete(session_id)

        assert store.get(session_id) is None

    def test_dump_restore(self) -> None:
        """dump() and restore() preserve sessions."""
        store = MemorySessionStore()
        session = store.create(auth={"identity": "user1", "tags": ["read"]})
        session_id = session.id

        dumped = store.dump()

        new_store = MemorySessionStore()
        new_store.restore(dumped)
        restored = new_store.get(session_id)

        assert restored is not None
        assert restored.id == session_id
        assert restored.auth == {"identity": "user1", "tags": ["read"]}
