"""Tests for bootstrap tail reconciliation with duplicate messages (#1229).

Verifies that bootstrap correctly handles repeated identical messages
(e.g., user says "ok" three times) without collapsing them into a single
identity or skipping/duplicating ingestion.
"""

from __future__ import annotations

import json

import pytest
import pytest_asyncio

from cortex.hippo.config import HippoConfig
from cortex.hippo.engine import HippoEngine


@pytest_asyncio.fixture
async def engine():
    """Provide a fresh HippoEngine with in-memory DB."""
    config = HippoConfig(
        enabled=True,
        db_path=":memory:",
        fresh_tail_count=10,
        max_tokens=50_000,
    )
    eng = HippoEngine(config=config)
    await eng.initialize(
        db_path=":memory:",
        owner_id="test-owner",
        conversation_id="dedup-test",
    )
    yield eng
    await eng.shutdown()


def _write_session_file(tmp_path, messages):
    """Write messages as a JSON array session file."""
    f = tmp_path / "session.json"
    f.write_text(json.dumps(messages), encoding="utf-8")
    return str(f)


class TestBootstrapDuplicateMessages:
    """Issue #1229: tail reconciliation must handle repeated identical messages."""

    @pytest.mark.asyncio
    async def test_three_identical_user_messages_all_ingested(self, engine, tmp_path):
        """Three 'ok' messages should all be ingested on first bootstrap."""
        messages = [
            {"role": "user", "content": "ok"},
            {"role": "assistant", "content": "Got it."},
            {"role": "user", "content": "ok"},
            {"role": "assistant", "content": "Understood."},
            {"role": "user", "content": "ok"},
            {"role": "assistant", "content": "Alright."},
        ]
        session_file = _write_session_file(tmp_path, messages)

        result = await engine.bootstrap(
            session_id="dedup-test",
            session_file=session_file,
        )

        assert result["bootstrapped"] is True
        assert result["message_count"] == 6

        # Verify all 6 messages are in the store
        stored = await engine.conversation_store.get_messages(
            engine._conversation.conversation_id, "test-owner"
        )
        assert len(stored) == 6

    @pytest.mark.asyncio
    async def test_re_bootstrap_with_duplicates_no_double_ingest(self, engine, tmp_path):
        """Re-bootstrapping the same file should be a no-op (already bootstrapped)."""
        messages = [
            {"role": "user", "content": "ok"},
            {"role": "assistant", "content": "Got it."},
            {"role": "user", "content": "ok"},
        ]
        session_file = _write_session_file(tmp_path, messages)

        result1 = await engine.bootstrap(
            session_id="dedup-test",
            session_file=session_file,
        )
        assert result1["bootstrapped"] is True
        assert result1["message_count"] == 3

        # Second bootstrap should be no-op (already bootstrapped flag set)
        result2 = await engine.bootstrap(
            session_id="dedup-test",
            session_file=session_file,
        )
        assert result2["bootstrapped"] is False
        assert result2["message_count"] == 0

    @pytest.mark.asyncio
    async def test_partial_ingest_then_bootstrap_completes(self, tmp_path):
        """If some messages are already ingested, bootstrap should add only new ones."""
        config = HippoConfig(
            enabled=True,
            db_path=":memory:",
            fresh_tail_count=10,
            max_tokens=50_000,
        )
        eng = HippoEngine(config=config)
        await eng.initialize(
            db_path=":memory:",
            owner_id="test-owner",
            conversation_id="partial-test",
        )

        try:
            conv = eng._conversation

            # Manually ingest 2 of the 5 messages (simulating partial prior ingest)
            await eng.conversation_store.create_message(
                conversation_id=conv.conversation_id,
                owner_id="test-owner",
                role="user",
                content="ok",
            )
            await eng.conversation_store.create_message(
                conversation_id=conv.conversation_id,
                owner_id="test-owner",
                role="assistant",
                content="Got it.",
            )

            # Now bootstrap with a file containing 5 messages (including 3 "ok"s)
            messages = [
                {"role": "user", "content": "ok"},
                {"role": "assistant", "content": "Got it."},
                {"role": "user", "content": "ok"},
                {"role": "assistant", "content": "Understood."},
                {"role": "user", "content": "ok"},
            ]
            session_file = _write_session_file(tmp_path, messages)

            result = await eng.bootstrap(
                session_id="partial-test",
                session_file=session_file,
            )

            assert result["bootstrapped"] is True
            # Should ingest exactly 3 new messages:
            # - 1st "ok" matches existing → consumed
            # - "Got it." matches existing → consumed
            # - 2nd "ok" → NEW
            # - "Understood." → NEW
            # - 3rd "ok" → NEW
            assert result["message_count"] == 3

            # Total in store: 2 (pre-existing) + 3 (new) = 5
            stored = await eng.conversation_store.get_messages(
                conv.conversation_id, "test-owner"
            )
            assert len(stored) == 5

        finally:
            await eng.shutdown()

    @pytest.mark.asyncio
    async def test_all_messages_unique_still_works(self, engine, tmp_path):
        """Unique messages should be ingested normally (regression check)."""
        messages = [
            {"role": "user", "content": "hello"},
            {"role": "assistant", "content": "hi there"},
            {"role": "user", "content": "how are you?"},
        ]
        session_file = _write_session_file(tmp_path, messages)

        result = await engine.bootstrap(
            session_id="dedup-test",
            session_file=session_file,
        )

        assert result["bootstrapped"] is True
        assert result["message_count"] == 3

    @pytest.mark.asyncio
    async def test_empty_content_duplicates(self, engine, tmp_path):
        """Empty-content messages with same role should be deduplicated correctly."""
        messages = [
            {"role": "assistant", "content": ""},
            {"role": "assistant", "content": ""},
            {"role": "assistant", "content": "real response"},
        ]
        session_file = _write_session_file(tmp_path, messages)

        result = await engine.bootstrap(
            session_id="dedup-test",
            session_file=session_file,
        )

        assert result["bootstrapped"] is True
        assert result["message_count"] == 3
