"""Tests for ThreadStore."""

from __future__ import annotations

import pytest

from koan.memory.thread import ThreadStore


@pytest.fixture
async def store():
    """Create an in-memory ThreadStore."""
    s = ThreadStore("sqlite+aiosqlite://")
    await s.init()
    yield s
    await s.close()


class TestThreadStore:
    async def test_append_and_retrieve(self, store: ThreadStore) -> None:
        await store.append("t1", role="user", content="Hello")
        await store.append("t1", role="assistant", content="Hi there!")

        messages = await store.get_messages("t1")
        assert len(messages) == 2
        assert messages[0].role == "user"
        assert messages[0].content == "Hello"
        assert messages[1].role == "assistant"
        assert messages[1].content == "Hi there!"

    async def test_message_ordering(self, store: ThreadStore) -> None:
        for i in range(5):
            await store.append("t1", role="user", content=f"msg-{i}")

        messages = await store.get_messages("t1")
        assert [m.content for m in messages] == [f"msg-{i}" for i in range(5)]

    async def test_separate_threads(self, store: ThreadStore) -> None:
        await store.append("t1", role="user", content="Thread 1")
        await store.append("t2", role="user", content="Thread 2")

        m1 = await store.get_messages("t1")
        m2 = await store.get_messages("t2")
        assert len(m1) == 1
        assert len(m2) == 1
        assert m1[0].content == "Thread 1"
        assert m2[0].content == "Thread 2"

    async def test_list_threads(self, store: ThreadStore) -> None:
        await store.append("t1", role="user", content="a")
        await store.append("t2", role="user", content="b")
        await store.append("t3", role="user", content="c")

        threads = await store.list_threads()
        assert set(threads) == {"t1", "t2", "t3"}

    async def test_list_threads_by_user(self, store: ThreadStore) -> None:
        await store.append("t1", role="user", content="a", user_id="alice")
        await store.append("t2", role="user", content="b", user_id="bob")
        await store.append("t3", role="user", content="c", user_id="alice")

        alice_threads = await store.list_threads(user_id="alice")
        assert set(alice_threads) == {"t1", "t3"}

    async def test_get_messages_with_limit(self, store: ThreadStore) -> None:
        for i in range(10):
            await store.append("t1", role="user", content=f"msg-{i}")

        messages = await store.get_messages("t1", limit=3)
        assert len(messages) == 3
        assert messages[0].content == "msg-0"

    async def test_delete_thread(self, store: ThreadStore) -> None:
        await store.append("t1", role="user", content="a")
        await store.append("t1", role="user", content="b")

        count = await store.delete_thread("t1")
        assert count == 2

        messages = await store.get_messages("t1")
        assert len(messages) == 0

    async def test_empty_thread(self, store: ThreadStore) -> None:
        messages = await store.get_messages("nonexistent")
        assert messages == []

    async def test_message_metadata(self, store: ThreadStore) -> None:
        await store.append("t1", role="user", content="test", metadata={"source": "web"})

        messages = await store.get_messages("t1")
        assert messages[0].metadata == {"source": "web"}

    async def test_message_has_id_and_thread_id(self, store: ThreadStore) -> None:
        msg = await store.append("t1", role="user", content="hi")
        assert msg.id is not None
        assert msg.thread_id == "t1"
