# 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 login, logout, session info endpoints on ServerApplication."""

from unittest.mock import MagicMock

from genro_asgi.server.server_app import ServerApplication
from genro_asgi.session import MemorySessionStore


class TestLoginEndpoints:
    """Tests for _server/login, _server/logout, _server/session endpoints."""

    def _make_app(self) -> tuple[ServerApplication, MagicMock]:
        """Create ServerApplication with mock server that has auth and session store."""
        mock_server = MagicMock()
        mock_server.config = {"main_app": None, "apps": {}}
        mock_server.session_store = MemorySessionStore(default_ttl=3600)
        mock_server.verify_credentials.return_value = {
            "identity": "admin",
            "tags": ["admin", "write"],
        }
        app = ServerApplication(mock_server)
        return app, mock_server

    def test_login_valid_credentials(self) -> None:
        """Login with valid credentials creates session and returns token."""
        app, mock_server = self._make_app()
        result = app.login(username="admin", password="secret")

        assert "session_id" in result
        assert result["identity"] == "admin"
        assert result["tags"] == ["admin", "write"]
        mock_server.verify_credentials.assert_called_once_with("admin", "secret")

    def test_login_invalid_credentials(self) -> None:
        """Login with invalid credentials returns error."""
        app, mock_server = self._make_app()
        mock_server.verify_credentials.return_value = None
        result = app.login(username="admin", password="wrong")

        assert "error" in result
        assert result["error"] == "Invalid credentials"

    def test_logout(self) -> None:
        """Logout deletes session and returns success."""
        app, mock_server = self._make_app()
        session = mock_server.session_store.create(
            auth={"identity": "admin", "tags": ["admin"]},
        )
        result = app.logout(session_id=session.id)

        assert result["status"] == "ok"
        assert mock_server.session_store.get(session.id) is None

    def test_logout_no_session(self) -> None:
        """Logout with invalid session_id returns error."""
        app, _ = self._make_app()
        result = app.logout(session_id="nonexistent")

        assert result["status"] == "ok"

    def test_session_info(self) -> None:
        """Session info returns session metadata and identity."""
        app, mock_server = self._make_app()
        session = mock_server.session_store.create(
            auth={"identity": "user1", "tags": ["read"]},
        )
        result = app.session_info(session_id=session.id)

        assert result["identity"] == "user1"
        assert result["tags"] == ["read"]
        assert "created_at" in result

    def test_session_info_no_session(self) -> None:
        """Session info with invalid session_id returns error."""
        app, _ = self._make_app()
        result = app.session_info(session_id="invalid")

        assert "error" in result
        assert result["error"] == "Session not found"
