# tests/core/services/test_session_service.py
"""Unit tests for the SessionService class."""
import pytest
from unittest.mock import MagicMock
from sqlalchemy.orm import Session
from sqlalchemy.exc import SQLAlchemyError

from app.core.services.session import SessionService
from app.db import models


@pytest.fixture
def session_service():
    return SessionService()


@pytest.fixture
def mock_db():
    db = MagicMock(spec=Session)
    db.add = MagicMock()
    db.commit = MagicMock()
    db.rollback = MagicMock()

    def refresh_side_effect(obj):
        # Simulate refresh populating id and created_at
        if not hasattr(obj, "_refreshed"):
            obj.id = 1
            obj._refreshed = True

    db.refresh = MagicMock(side_effect=refresh_side_effect)
    return db


class TestCreateSession:
    """Tests for SessionService.create_session."""

    def test_create_session_default_feature_name(self, session_service, mock_db):
        """Tests that the default feature_name is 'default' when not provided."""
        result = session_service.create_session(
            db=mock_db,
            user_id="user_123",
            provider_name="gemini"
        )
        mock_db.add.assert_called_once()
        added_session = mock_db.add.call_args[0][0]
        assert isinstance(added_session, models.Session)
        assert added_session.user_id == "user_123"
        assert added_session.provider_name == "gemini"
        assert added_session.feature_name == "default"

    def test_create_session_with_coding_assistant_namespace(self, session_service, mock_db):
        """Tests creating a session with feature_name='coding_assistant'."""
        result = session_service.create_session(
            db=mock_db,
            user_id="user_abc",
            provider_name="deepseek",
            feature_name="coding_assistant"
        )
        mock_db.add.assert_called_once()
        added_session = mock_db.add.call_args[0][0]
        assert added_session.feature_name == "coding_assistant"
        mock_db.commit.assert_called_once()

    def test_create_session_with_voice_chat_namespace(self, session_service, mock_db):
        """Tests creating a session with feature_name='voice_chat'."""
        result = session_service.create_session(
            db=mock_db,
            user_id="user_xyz",
            provider_name="gemini",
            feature_name="voice_chat"
        )
        added_session = mock_db.add.call_args[0][0]
        assert added_session.feature_name == "voice_chat"

    def test_create_session_sets_title(self, session_service, mock_db):
        """Tests that the session is assigned a default title on creation."""
        session_service.create_session(
            db=mock_db,
            user_id="user_title",
            provider_name="deepseek"
        )
        added_session = mock_db.add.call_args[0][0]
        assert added_session.title is not None
        assert len(added_session.title) > 0

    def test_create_session_db_error_triggers_rollback(self, session_service, mock_db):
        """Tests that a SQLAlchemyError triggers a rollback."""
        mock_db.commit.side_effect = SQLAlchemyError("DB write failed")

        with pytest.raises(SQLAlchemyError):
            session_service.create_session(
                db=mock_db,
                user_id="user_err",
                provider_name="deepseek"
            )

        mock_db.rollback.assert_called_once()
