# tests/fixtures/message_fixtures.py
"""
Messaging-related test fixtures.

Note: Fixtures should NOT use db.expunge() as it breaks lazy loading.
See tests/conftest.py for details on fixture best practices.
"""

from datetime import UTC

import pytest

from app.modules.messaging.models import (
    Conversation,
    ConversationParticipant,
    ConversationType,
    Message,
    MessageAttachment,
    ParticipantType,
)


@pytest.fixture
def test_conversation_admin_store(db, test_admin, test_store_user, test_store):
    """Create a test conversation between admin and store user."""
    conversation = Conversation(
        conversation_type=ConversationType.ADMIN_STORE,
        subject="Test Admin-Store Conversation",
        store_id=test_store.id,
    )
    db.add(conversation)
    db.commit()
    db.refresh(conversation)

    # Add admin participant
    admin_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.ADMIN,
        participant_id=test_admin.id,
    )
    db.add(admin_participant)

    # Add store participant
    store_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.STORE,
        participant_id=test_store_user.id,
        store_id=test_store.id,
    )
    db.add(store_participant)

    db.commit()
    db.refresh(conversation)
    return conversation


@pytest.fixture
def test_conversation_store_customer(db, test_store_user, test_customer, test_store):
    """Create a test conversation between store and customer."""
    conversation = Conversation(
        conversation_type=ConversationType.STORE_CUSTOMER,
        subject="Test Store-Customer Conversation",
        store_id=test_store.id,
    )
    db.add(conversation)
    db.commit()
    db.refresh(conversation)

    # Add store participant
    store_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.STORE,
        participant_id=test_store_user.id,
        store_id=test_store.id,
    )
    db.add(store_participant)

    # Add customer participant
    customer_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.CUSTOMER,
        participant_id=test_customer.id,
    )
    db.add(customer_participant)

    db.commit()
    db.refresh(conversation)
    return conversation


@pytest.fixture
def test_conversation_admin_customer(db, test_admin, test_customer, test_store):
    """Create a test conversation between admin and customer."""
    conversation = Conversation(
        conversation_type=ConversationType.ADMIN_CUSTOMER,
        subject="Test Admin-Customer Conversation",
        store_id=test_store.id,
    )
    db.add(conversation)
    db.commit()
    db.refresh(conversation)

    # Add admin participant
    admin_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.ADMIN,
        participant_id=test_admin.id,
    )
    db.add(admin_participant)

    # Add customer participant
    customer_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.CUSTOMER,
        participant_id=test_customer.id,
    )
    db.add(customer_participant)

    db.commit()
    db.refresh(conversation)
    return conversation


@pytest.fixture
def test_message(db, test_conversation_admin_store, test_admin):
    """Create a test message in a conversation."""
    message = Message(
        conversation_id=test_conversation_admin_store.id,
        sender_type=ParticipantType.ADMIN,
        sender_id=test_admin.id,
        content="This is a test message from admin.",
    )
    db.add(message)

    # Update conversation stats
    test_conversation_admin_store.message_count = 1
    test_conversation_admin_store.last_message_at = message.created_at

    db.commit()
    db.refresh(message)
    return message


@pytest.fixture
def test_message_with_attachment(db, test_conversation_admin_store, test_admin):
    """Create a test message with an attachment."""
    message = Message(
        conversation_id=test_conversation_admin_store.id,
        sender_type=ParticipantType.ADMIN,
        sender_id=test_admin.id,
        content="This message has an attachment.",
    )
    db.add(message)
    db.commit()
    db.refresh(message)

    attachment = MessageAttachment(
        message_id=message.id,
        filename="test_file_abc123.pdf",
        original_filename="test_document.pdf",
        file_path="/uploads/messages/2025/01/1/test_file_abc123.pdf",
        file_size=12345,
        mime_type="application/pdf",
        is_image=False,
    )
    db.add(attachment)
    db.commit()
    db.refresh(message)

    return message


@pytest.fixture
def closed_conversation(db, test_admin, test_store_user, test_store):
    """Create a closed conversation."""
    from datetime import datetime

    conversation = Conversation(
        conversation_type=ConversationType.ADMIN_STORE,
        subject="Closed Conversation",
        store_id=test_store.id,
        is_closed=True,
        closed_at=datetime.now(UTC),
        closed_by_type=ParticipantType.ADMIN,
        closed_by_id=test_admin.id,
    )
    db.add(conversation)
    db.commit()
    db.refresh(conversation)

    # Add participants
    admin_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.ADMIN,
        participant_id=test_admin.id,
    )
    db.add(admin_participant)

    store_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.STORE,
        participant_id=test_store_user.id,
        store_id=test_store.id,
    )
    db.add(store_participant)

    db.commit()
    db.refresh(conversation)
    return conversation


@pytest.fixture
def multiple_conversations(db, test_admin, test_store_user, test_customer, test_store):
    """Create multiple conversations of different types."""
    conversations = []

    # Create 3 admin-store conversations
    for i in range(3):
        conv = Conversation(
            conversation_type=ConversationType.ADMIN_STORE,
            subject=f"Admin-Store Conversation {i+1}",
            store_id=test_store.id,
        )
        db.add(conv)  # noqa: PERF006
        db.commit()
        db.refresh(conv)

        db.add(  # noqa: PERF006
            ConversationParticipant(
                conversation_id=conv.id,
                participant_type=ParticipantType.ADMIN,
                participant_id=test_admin.id,
            )
        )
        db.add(  # noqa: PERF006
            ConversationParticipant(
                conversation_id=conv.id,
                participant_type=ParticipantType.STORE,
                participant_id=test_store_user.id,
                store_id=test_store.id,
            )
        )
        conversations.append(conv)

    # Create 2 store-customer conversations
    for i in range(2):
        conv = Conversation(
            conversation_type=ConversationType.STORE_CUSTOMER,
            subject=f"Store-Customer Conversation {i+1}",
            store_id=test_store.id,
        )
        db.add(conv)  # noqa: PERF006
        db.commit()
        db.refresh(conv)

        db.add(  # noqa: PERF006
            ConversationParticipant(
                conversation_id=conv.id,
                participant_type=ParticipantType.STORE,
                participant_id=test_store_user.id,
                store_id=test_store.id,
            )
        )
        db.add(  # noqa: PERF006
            ConversationParticipant(
                conversation_id=conv.id,
                participant_type=ParticipantType.CUSTOMER,
                participant_id=test_customer.id,
            )
        )
        conversations.append(conv)

    db.commit()

    # Refresh all
    for conv in conversations:
        db.refresh(conv)

    return conversations


@pytest.fixture
def store_api_conversation(db, test_admin, test_store_user, test_store_with_store_user):
    """Create a conversation for store API tests (uses store from store_user_headers)."""
    conversation = Conversation(
        conversation_type=ConversationType.ADMIN_STORE,
        subject="Store API Test Conversation",
        store_id=test_store_with_store_user.id,
    )
    db.add(conversation)
    db.commit()
    db.refresh(conversation)

    # Add admin participant
    admin_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.ADMIN,
        participant_id=test_admin.id,
    )
    db.add(admin_participant)

    # Add store participant (uses test_store_user which store_user_headers uses)
    store_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.STORE,
        participant_id=test_store_user.id,
        store_id=test_store_with_store_user.id,
    )
    db.add(store_participant)

    db.commit()
    db.refresh(conversation)
    return conversation


@pytest.fixture
def store_api_closed_conversation(db, test_admin, test_store_user, test_store_with_store_user):
    """Create a closed conversation for store API tests."""
    from datetime import datetime

    conversation = Conversation(
        conversation_type=ConversationType.ADMIN_STORE,
        subject="Store API Closed Conversation",
        store_id=test_store_with_store_user.id,
        is_closed=True,
        closed_at=datetime.now(UTC),
        closed_by_type=ParticipantType.ADMIN,
        closed_by_id=test_admin.id,
    )
    db.add(conversation)
    db.commit()
    db.refresh(conversation)

    # Add participants
    admin_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.ADMIN,
        participant_id=test_admin.id,
    )
    db.add(admin_participant)

    store_participant = ConversationParticipant(
        conversation_id=conversation.id,
        participant_type=ParticipantType.STORE,
        participant_id=test_store_user.id,
        store_id=test_store_with_store_user.id,
    )
    db.add(store_participant)

    db.commit()
    db.refresh(conversation)
    return conversation
