from unittest.mock import ANY, patch

import pytest
from faker import Faker
from sqlalchemy.orm import Session

from models.enums import ConversationFromSource, FeedbackRating, InvokeFrom
from models.model import MessageFeedback
from services.app_service import AppService, CreateAppParams
from services.errors.message import (
    FirstMessageNotExistsError,
    LastMessageNotExistsError,
    MessageNotExistsError,
    SuggestedQuestionsAfterAnswerDisabledError,
)
from services.message_service import MessageService
from tests.test_containers_integration_tests.helpers import generate_valid_password


class TestMessageService:
    """Integration tests for MessageService using testcontainers."""

    @pytest.fixture
    def mock_external_service_dependencies(self):
        """Mock setup for external service dependencies."""
        with (
            patch("services.account_service.FeatureService") as mock_account_feature_service,
            patch("services.message_service.ModelManager.for_tenant") as mock_model_manager,
            patch("services.message_service.WorkflowService") as mock_workflow_service,
            patch("services.message_service.AdvancedChatAppConfigManager") as mock_app_config_manager,
            patch("services.message_service.LLMGenerator") as mock_llm_generator,
            patch("services.message_service.TraceQueueManager") as mock_trace_manager_class,
            patch("services.message_service.TokenBufferMemory") as mock_token_buffer_memory,
        ):
            # Setup default mock returns
            mock_account_feature_service.get_features.return_value.billing.enabled = False

            # Mock ModelManager
            mock_model_instance = mock_model_manager.return_value.get_default_model_instance.return_value
            mock_model_instance.get_tts_voices.return_value = [{"value": "test-voice"}]

            # Mock get_model_instance method as well
            mock_model_manager.return_value.get_model_instance.return_value = mock_model_instance

            # Mock WorkflowService
            mock_workflow = mock_workflow_service.return_value.get_published_workflow.return_value
            mock_workflow_service.return_value.get_draft_workflow.return_value = mock_workflow

            # Mock AdvancedChatAppConfigManager
            mock_app_config = mock_app_config_manager.get_app_config.return_value
            mock_app_config.additional_features.suggested_questions_after_answer = True

            # Mock LLMGenerator
            mock_llm_generator.generate_suggested_questions_after_answer.return_value = ["Question 1", "Question 2"]

            # Mock TraceQueueManager
            mock_trace_manager_instance = mock_trace_manager_class.return_value

            # Mock TokenBufferMemory
            mock_memory_instance = mock_token_buffer_memory.return_value
            mock_memory_instance.get_history_prompt_text.return_value = "Mocked history prompt"

            yield {
                "account_feature_service": mock_account_feature_service,
                "model_manager": mock_model_manager,
                "workflow_service": mock_workflow_service,
                "app_config_manager": mock_app_config_manager,
                "llm_generator": mock_llm_generator,
                "trace_manager_class": mock_trace_manager_class,
                "trace_manager_instance": mock_trace_manager_instance,
                "token_buffer_memory": mock_token_buffer_memory,
                # "current_user": mock_current_user,
            }

    def _create_test_app_and_account(self, db_session_with_containers: Session, mock_external_service_dependencies):
        """
        Helper method to create a test app and account for testing.

        Args:
            db_session_with_containers: Database session from testcontainers infrastructure
            mock_external_service_dependencies: Mock dependencies

        Returns:
            tuple: (app, account) - Created app and account instances
        """
        fake = Faker()

        # Setup mocks for account creation
        mock_external_service_dependencies[
            "account_feature_service"
        ].get_system_features.return_value.is_allow_register = True

        # Create account and tenant first
        from services.account_service import AccountService, TenantService

        account = AccountService.create_account(
            email=fake.email(),
            name=fake.name(),
            interface_language="en-US",
            password=generate_valid_password(fake),
            session=db_session_with_containers,
        )
        TenantService.create_owner_tenant_if_not_exist(account, name=fake.company(), session=db_session_with_containers)
        tenant = account.current_tenant

        # Setup app creation arguments
        app_args = CreateAppParams(
            name=fake.company(),
            description=fake.text(max_nb_chars=100),
            mode="advanced-chat",  # Use advanced-chat mode to use mocked workflow,
            icon_type="emoji",
            icon="🤖",
            icon_background="#FF6B6B",
            api_rph=100,
            api_rpm=10,
        )

        # Create app
        app_service = AppService()
        app = app_service.create_app(tenant.id, app_args, account, session=db_session_with_containers)

        # Setup current_user mock
        self._mock_current_user(mock_external_service_dependencies, account.id, tenant.id)

        return app, account

    def _mock_current_user(self, mock_external_service_dependencies, account_id, tenant_id):
        """
        Helper method to mock the current user for testing.
        """
        # mock_external_service_dependencies["current_user"].id = account_id
        # mock_external_service_dependencies["current_user"].current_tenant_id = tenant_id

    def _create_test_conversation(self, db_session_with_containers: Session, app, account, fake):
        """
        Helper method to create a test conversation with all required fields.
        """
        from models.model import Conversation

        conversation = Conversation(
            app_id=app.id,
            app_model_config_id=None,
            model_provider=None,
            model_id="",
            override_model_configs=None,
            mode=app.mode,
            name=fake.sentence(),
            inputs={},
            introduction="",
            system_instruction="",
            system_instruction_tokens=0,
            status="normal",
            invoke_from=InvokeFrom.EXPLORE,
            from_source=ConversationFromSource.CONSOLE,
            from_end_user_id=None,
            from_account_id=account.id,
        )

        db_session_with_containers.add(conversation)
        db_session_with_containers.flush()
        return conversation

    def _create_test_message(self, db_session_with_containers: Session, app, conversation, account, fake):
        """
        Helper method to create a test message with all required fields.
        """
        import json

        from models.model import Message

        message = Message(
            app_id=app.id,
            model_provider=None,
            model_id="",
            override_model_configs=None,
            conversation_id=conversation.id,
            inputs={},
            query=fake.sentence(),
            message=json.dumps([{"role": "user", "text": fake.sentence()}]),
            message_tokens=0,
            message_unit_price=0,
            message_price_unit=0.001,
            answer=fake.text(max_nb_chars=200),
            answer_tokens=0,
            answer_unit_price=0,
            answer_price_unit=0.001,
            parent_message_id=None,
            provider_response_latency=0,
            total_price=0,
            currency="USD",
            invoke_from=InvokeFrom.EXPLORE,
            from_source=ConversationFromSource.CONSOLE,
            from_end_user_id=None,
            from_account_id=account.id,
        )

        db_session_with_containers.add(message)
        db_session_with_containers.commit()
        return message

    def test_pagination_by_first_id_success(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test successful pagination by first ID.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and multiple messages
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        messages = []
        for i in range(5):
            message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)
            messages.append(message)

        # Test pagination by first ID
        result = MessageService.pagination_by_first_id(
            app_model=app,
            user=account,
            conversation_id=conversation.id,
            first_id=messages[2].id,  # Use middle message as first_id
            limit=2,
            order="asc",
            session=db_session_with_containers,
        )

        # Verify results
        assert result.limit == 2
        assert len(result.data) == 2
        # total 5, from the middle, no more
        assert result.has_more is False
        # Verify messages are in ascending order
        assert result.data[0].created_at <= result.data[1].created_at

    def test_pagination_by_first_id_no_user(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test pagination by first ID when no user is provided.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Test pagination with no user
        result = MessageService.pagination_by_first_id(
            app_model=app,
            user=None,
            conversation_id=fake.uuid4(),
            first_id=None,
            limit=10,
            session=db_session_with_containers,
        )

        # Verify empty result
        assert result.limit == 10
        assert len(result.data) == 0
        assert result.has_more is False

    def test_pagination_by_first_id_no_conversation_id(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test pagination by first ID when no conversation ID is provided.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Test pagination with no conversation ID
        result = MessageService.pagination_by_first_id(
            app_model=app,
            user=account,
            conversation_id="",
            first_id=None,
            limit=10,
            session=db_session_with_containers,
        )

        # Verify empty result
        assert result.limit == 10
        assert len(result.data) == 0
        assert result.has_more is False

    def test_pagination_by_first_id_invalid_first_id(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test pagination by first ID with invalid first_id.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Test pagination with invalid first_id
        with pytest.raises(FirstMessageNotExistsError):
            MessageService.pagination_by_first_id(
                app_model=app,
                user=account,
                conversation_id=conversation.id,
                first_id=fake.uuid4(),  # Non-existent message ID
                limit=10,
                session=db_session_with_containers,
            )

    def test_pagination_by_last_id_success(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test successful pagination by last ID.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and multiple messages
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        messages = []
        for i in range(5):
            message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)
            messages.append(message)

        # Test pagination by last ID
        result = MessageService.pagination_by_last_id(
            app_model=app,
            user=account,
            last_id=messages[2].id,  # Use middle message as last_id
            limit=2,
            conversation_id=conversation.id,
            session=db_session_with_containers,
        )

        # Verify results
        assert result.limit == 2
        assert len(result.data) == 2
        # total 5, from the middle, no more
        assert result.has_more is False
        # Verify messages are in descending order
        assert result.data[0].created_at >= result.data[1].created_at

    def test_pagination_by_last_id_with_include_ids(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test pagination by last ID with include_ids filter.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and multiple messages
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        messages = []
        for i in range(5):
            message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)
            messages.append(message)

        # Test pagination with include_ids
        include_ids = [messages[0].id, messages[1].id, messages[2].id]
        result = MessageService.pagination_by_last_id(
            app_model=app,
            user=account,
            last_id=messages[1].id,
            limit=2,
            include_ids=include_ids,
            session=db_session_with_containers,
        )

        # Verify results
        assert result.limit == 2
        assert len(result.data) <= 2
        # Verify all returned messages are in include_ids
        for message in result.data:
            assert message.id in include_ids

    def test_pagination_by_last_id_no_user(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test pagination by last ID when no user is provided.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Test pagination with no user,
        result = MessageService.pagination_by_last_id(
            app_model=app, user=None, last_id=None, limit=10, session=db_session_with_containers
        )

        # Verify empty result
        assert result.limit == 10
        assert len(result.data) == 0
        assert result.has_more is False

    def test_pagination_by_last_id_invalid_last_id(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test pagination by last ID with invalid last_id.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Test pagination with invalid last_id
        with pytest.raises(LastMessageNotExistsError):
            MessageService.pagination_by_last_id(
                app_model=app,
                user=account,
                last_id=fake.uuid4(),  # Non-existent message ID
                limit=10,
                conversation_id=conversation.id,
                session=db_session_with_containers,
            )

    def test_create_feedback_success(self, db_session_with_containers: Session, mock_external_service_dependencies):
        """
        Test successful creation of feedback.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Create feedback
        rating = FeedbackRating.LIKE
        content = fake.text(max_nb_chars=100)
        feedback = MessageService.create_feedback(
            app_model=app,
            message_id=message.id,
            user=account,
            rating=rating,
            content=content,
            session=db_session_with_containers,
        )

        # Verify feedback was created correctly
        assert feedback.app_id == app.id
        assert feedback.conversation_id == conversation.id
        assert feedback.message_id == message.id
        assert feedback.rating == rating
        assert feedback.content == content
        assert feedback.from_source == "admin"
        assert feedback.from_account_id == account.id
        assert feedback.from_end_user_id is None

    def test_create_feedback_no_user(self, db_session_with_containers: Session, mock_external_service_dependencies):
        """
        Test creating feedback when no user is provided.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Test creating feedback with no user
        with pytest.raises(ValueError, match="user cannot be None"):
            MessageService.create_feedback(
                app_model=app,
                message_id=message.id,
                user=None,
                rating=FeedbackRating.LIKE,
                content=fake.text(max_nb_chars=100),
                session=db_session_with_containers,
            )

    def test_create_feedback_update_existing(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test updating existing feedback.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Create initial feedback
        initial_rating = FeedbackRating.LIKE
        initial_content = fake.text(max_nb_chars=100)
        feedback = MessageService.create_feedback(
            app_model=app,
            message_id=message.id,
            user=account,
            rating=initial_rating,
            content=initial_content,
            session=db_session_with_containers,
        )

        # Update feedback
        updated_rating = FeedbackRating.DISLIKE
        updated_content = fake.text(max_nb_chars=100)
        updated_feedback = MessageService.create_feedback(
            app_model=app,
            message_id=message.id,
            user=account,
            rating=updated_rating,
            content=updated_content,
            session=db_session_with_containers,
        )

        # Verify feedback was updated correctly
        assert updated_feedback.id == feedback.id
        assert updated_feedback.rating == updated_rating
        assert updated_feedback.content == updated_content
        assert updated_feedback.rating != initial_rating
        assert updated_feedback.content != initial_content

    def test_create_feedback_delete_existing(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test deleting existing feedback by setting rating to None.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Create initial feedback
        feedback = MessageService.create_feedback(
            app_model=app,
            message_id=message.id,
            user=account,
            rating=FeedbackRating.LIKE,
            content=fake.text(max_nb_chars=100),
            session=db_session_with_containers,
        )

        # Delete feedback by setting rating to None,
        MessageService.create_feedback(
            app_model=app,
            message_id=message.id,
            user=account,
            rating=None,
            content=None,
            session=db_session_with_containers,
        )

        # Verify feedback was deleted

        deleted_feedback = (
            db_session_with_containers.query(MessageFeedback).where(MessageFeedback.id == feedback.id).first()
        )
        assert deleted_feedback is None

    def test_create_feedback_no_rating_when_not_exists(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test creating feedback with no rating when feedback doesn't exist.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Test creating feedback with no rating when no feedback exists
        with pytest.raises(ValueError, match="rating cannot be None when feedback not exists"):
            MessageService.create_feedback(
                app_model=app,
                message_id=message.id,
                user=account,
                rating=None,
                content=None,
                session=db_session_with_containers,
            )

    def test_get_all_messages_feedbacks_success(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test successful retrieval of all message feedbacks.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create multiple conversations and messages with feedbacks
        feedbacks = []
        for i in range(3):
            conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
            message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

            feedback = MessageService.create_feedback(
                app_model=app,
                message_id=message.id,
                user=account,
                rating=FeedbackRating.LIKE if i % 2 == 0 else FeedbackRating.DISLIKE,
                content=f"Feedback {i}: {fake.text(max_nb_chars=50)}",
                session=db_session_with_containers,
            )
            feedbacks.append(feedback)

        # Get all feedbacks,
        result = MessageService.get_all_messages_feedbacks(app, page=1, limit=10, session=db_session_with_containers)

        # Verify results
        assert len(result) == 3

        # Verify feedbacks are ordered by created_at desc
        for i in range(len(result) - 1):
            assert result[i]["created_at"] >= result[i + 1]["created_at"]

    def test_get_all_messages_feedbacks_pagination(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test pagination of message feedbacks.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create multiple conversations and messages with feedbacks
        for i in range(5):
            conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
            message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

            MessageService.create_feedback(
                app_model=app,
                message_id=message.id,
                user=account,
                rating=FeedbackRating.LIKE,
                content=f"Feedback {i}",
                session=db_session_with_containers,
            )

        # Get feedbacks with pagination
        result_page_1 = MessageService.get_all_messages_feedbacks(
            app, page=1, limit=3, session=db_session_with_containers
        )
        result_page_2 = MessageService.get_all_messages_feedbacks(
            app, page=2, limit=3, session=db_session_with_containers
        )

        # Verify pagination results
        assert len(result_page_1) == 3
        assert len(result_page_2) == 2

        # Verify no overlap between pages
        page_1_ids = {feedback["id"] for feedback in result_page_1}
        page_2_ids = {feedback["id"] for feedback in result_page_2}
        assert len(page_1_ids.intersection(page_2_ids)) == 0

    def test_get_message_success(self, db_session_with_containers: Session, mock_external_service_dependencies):
        """
        Test successful retrieval of message.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Get message,
        retrieved_message = MessageService.get_message(
            app_model=app, user=account, message_id=message.id, session=db_session_with_containers
        )

        # Verify message was retrieved correctly
        assert retrieved_message.id == message.id
        assert retrieved_message.app_id == app.id
        assert retrieved_message.conversation_id == conversation.id
        assert retrieved_message.from_source == "console"
        assert retrieved_message.from_account_id == account.id

    def test_get_message_not_exists(self, db_session_with_containers: Session, mock_external_service_dependencies):
        """
        Test getting message that doesn't exist.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Test getting non-existent message
        with pytest.raises(MessageNotExistsError):
            MessageService.get_message(
                app_model=app, user=account, message_id=fake.uuid4(), session=db_session_with_containers
            )

    def test_get_message_wrong_user(self, db_session_with_containers: Session, mock_external_service_dependencies):
        """
        Test getting message with wrong user (different account).
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Create another account
        from services.account_service import AccountService, TenantService

        other_account = AccountService.create_account(
            email=fake.email(),
            name=fake.name(),
            interface_language="en-US",
            password=generate_valid_password(fake),
            session=db_session_with_containers,
        )
        TenantService.create_owner_tenant_if_not_exist(
            other_account, name=fake.company(), session=db_session_with_containers
        )

        # Test getting message with different user
        with pytest.raises(MessageNotExistsError):
            MessageService.get_message(
                app_model=app, user=other_account, message_id=message.id, session=db_session_with_containers
            )

    def test_get_suggested_questions_after_answer_success(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test successful generation of suggested questions after answer.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Mock the LLMGenerator to return specific questions
        mock_questions = ["What is AI?", "How does machine learning work?", "Tell me about neural networks"]
        mock_external_service_dependencies[
            "llm_generator"
        ].generate_suggested_questions_after_answer.return_value = mock_questions

        # Get suggested questions
        from core.app.entities.app_invoke_entities import InvokeFrom

        result = MessageService.get_suggested_questions_after_answer(
            app_model=app,
            user=account,
            message_id=message.id,
            invoke_from=InvokeFrom.SERVICE_API,
            session=db_session_with_containers,
        )

        # Verify results
        assert result == mock_questions

        # Verify LLMGenerator was called
        mock_external_service_dependencies[
            "llm_generator"
        ].generate_suggested_questions_after_answer.assert_called_once()

        # Verify TraceQueueManager was called
        mock_external_service_dependencies["trace_manager_instance"].add_trace_task.assert_called_once()

    def test_get_suggested_questions_after_answer_no_user(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test getting suggested questions when no user is provided.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Test getting suggested questions with no user
        from core.app.entities.app_invoke_entities import InvokeFrom

        with pytest.raises(ValueError, match="user cannot be None"):
            MessageService.get_suggested_questions_after_answer(
                app_model=app,
                user=None,
                message_id=message.id,
                invoke_from=InvokeFrom.SERVICE_API,
                session=db_session_with_containers,
            )

    def test_get_suggested_questions_after_answer_disabled(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test getting suggested questions when feature is disabled.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Mock the feature to be disabled
        mock_external_service_dependencies[
            "app_config_manager"
        ].get_app_config.return_value.additional_features.suggested_questions_after_answer = False

        # Test getting suggested questions when feature is disabled
        from core.app.entities.app_invoke_entities import InvokeFrom

        with pytest.raises(SuggestedQuestionsAfterAnswerDisabledError):
            MessageService.get_suggested_questions_after_answer(
                app_model=app,
                user=account,
                message_id=message.id,
                invoke_from=InvokeFrom.SERVICE_API,
                session=db_session_with_containers,
            )

    def test_get_suggested_questions_after_answer_no_workflow(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test getting suggested questions when no workflow exists.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Mock no workflow
        mock_external_service_dependencies["workflow_service"].return_value.get_published_workflow.return_value = None

        # Get suggested questions (should return empty list)
        from core.app.entities.app_invoke_entities import InvokeFrom

        result = MessageService.get_suggested_questions_after_answer(
            app_model=app,
            user=account,
            message_id=message.id,
            invoke_from=InvokeFrom.SERVICE_API,
            session=db_session_with_containers,
        )

        # Verify empty result
        assert result == []

    def test_get_suggested_questions_after_answer_debugger_mode(
        self, db_session_with_containers: Session, mock_external_service_dependencies
    ):
        """
        Test getting suggested questions in debugger mode.
        """
        fake = Faker()
        app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies)

        # Create a conversation and message
        conversation = self._create_test_conversation(db_session_with_containers, app, account, fake)
        message = self._create_test_message(db_session_with_containers, app, conversation, account, fake)

        # Mock questions
        mock_questions = ["Debug question 1", "Debug question 2"]
        mock_external_service_dependencies[
            "llm_generator"
        ].generate_suggested_questions_after_answer.return_value = mock_questions

        # Get suggested questions in debugger mode
        from core.app.entities.app_invoke_entities import InvokeFrom

        result = MessageService.get_suggested_questions_after_answer(
            app_model=app,
            user=account,
            message_id=message.id,
            invoke_from=InvokeFrom.DEBUGGER,
            session=db_session_with_containers,
        )

        # Verify results
        assert result == mock_questions

        # Verify draft workflow was used instead of published workflow
        mock_external_service_dependencies["workflow_service"].return_value.get_draft_workflow.assert_called_once_with(
            app_model=app, session=ANY
        )

        # Verify TraceQueueManager was called
        mock_external_service_dependencies["trace_manager_instance"].add_trace_task.assert_called_once()
