"""
Tests for ConversationStore — conversations, messages, and message parts.

Issues: #801, #1164
"""

from __future__ import annotations

import pytest
import pytest_asyncio

from cortex.hippo.config import HippoConfig
from cortex.hippo.db.connection import HippoDatabase
from cortex.hippo.store.conversation_store import ConversationStore


@pytest_asyncio.fixture
async def store():
    """Provide a ConversationStore backed by an in-memory DB."""
    config = HippoConfig(db_path=":memory:")
    db = HippoDatabase(config)
    await db.initialize()
    cs = ConversationStore(db.conn)
    yield cs
    await db.close()


@pytest.mark.asyncio
async def test_get_or_create_conversation(store: ConversationStore):
    conv = await store.get_or_create_conversation("owner1", "sess1")
    assert conv.owner_id == "owner1"
    assert conv.session_id == "sess1"

    # Same call returns same conversation
    conv2 = await store.get_or_create_conversation("owner1", "sess1")
    assert conv2.conversation_id == conv.conversation_id


@pytest.mark.asyncio
async def test_create_and_get_message(store: ConversationStore):
    conv = await store.get_or_create_conversation("owner1", "sess1")
    msg = await store.create_message(conv.conversation_id, "owner1", "user", "hello")
    assert msg.role == "user"
    assert msg.content == "hello"
    assert msg.seq == 1

    fetched = await store.get_message_by_id(msg.message_id)
    assert fetched is not None
    assert fetched.content == "hello"


# ── Message Parts ──────────────────────────────────────────────────


@pytest.mark.asyncio
async def test_create_and_get_message_parts(store: ConversationStore):
    conv = await store.get_or_create_conversation("owner1", "sess1")
    msg = await store.create_message(conv.conversation_id, "owner1", "assistant", "response")

    parts = [
        {"part_type": "text", "text_content": "Hello there"},
        {"part_type": "tool", "tool_name": "web_search", "tool_call_id": "tc_1",
         "tool_input": '{"q":"test"}', "tool_output": "results"},
        {"part_type": "reasoning", "text_content": "Let me think..."},
    ]

    ids = await store.create_message_parts(msg.message_id, parts)
    assert len(ids) == 3

    fetched = await store.get_message_parts(msg.message_id)
    assert len(fetched) == 3
    assert fetched[0]["part_type"] == "text"
    assert fetched[0]["text_content"] == "Hello there"
    assert fetched[1]["part_type"] == "tool"
    assert fetched[1]["tool_name"] == "web_search"
    assert fetched[1]["tool_call_id"] == "tc_1"
    assert fetched[2]["part_type"] == "reasoning"


@pytest.mark.asyncio
async def test_message_parts_ordinal(store: ConversationStore):
    conv = await store.get_or_create_conversation("owner1", "sess1")
    msg = await store.create_message(conv.conversation_id, "owner1", "assistant", "x")

    parts = [
        {"ordinal": 2, "part_type": "text", "text_content": "second"},
        {"ordinal": 0, "part_type": "text", "text_content": "first"},
        {"ordinal": 1, "part_type": "text", "text_content": "middle"},
    ]
    await store.create_message_parts(msg.message_id, parts)

    fetched = await store.get_message_parts(msg.message_id)
    assert [p["text_content"] for p in fetched] == ["first", "middle", "second"]


@pytest.mark.asyncio
async def test_message_parts_bulk(store: ConversationStore):
    conv = await store.get_or_create_conversation("owner1", "sess1")
    msg1 = await store.create_message(conv.conversation_id, "owner1", "user", "q1")
    msg2 = await store.create_message(conv.conversation_id, "owner1", "assistant", "a1")
    msg3 = await store.create_message(conv.conversation_id, "owner1", "user", "q2")

    await store.create_message_parts(msg1.message_id, [
        {"part_type": "text", "text_content": "part1-1"},
    ])
    await store.create_message_parts(msg2.message_id, [
        {"part_type": "text", "text_content": "part2-1"},
        {"part_type": "tool", "tool_name": "exec", "text_content": "part2-2"},
    ])
    # msg3 has no parts

    bulk = await store.get_message_parts_bulk([msg1.message_id, msg2.message_id, msg3.message_id])
    assert len(bulk[msg1.message_id]) == 1
    assert len(bulk[msg2.message_id]) == 2
    assert len(bulk[msg3.message_id]) == 0


@pytest.mark.asyncio
async def test_message_parts_empty_list(store: ConversationStore):
    conv = await store.get_or_create_conversation("owner1", "sess1")
    msg = await store.create_message(conv.conversation_id, "owner1", "user", "x")

    ids = await store.create_message_parts(msg.message_id, [])
    assert ids == []

    fetched = await store.get_message_parts(msg.message_id)
    assert fetched == []


@pytest.mark.asyncio
async def test_message_parts_bulk_empty(store: ConversationStore):
    result = await store.get_message_parts_bulk([])
    assert result == {}
