"""
Tests for DB pragmas and performance indexes.

Issue: #1185
"""

from __future__ import annotations

import pytest
import pytest_asyncio

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


@pytest.fixture
def perf_config() -> HippoConfig:
    return HippoConfig(
        enabled=True,
        db_path=":memory:",
        pragma_cache_size=-8192,
        pragma_mmap_size=268435456,
    )


@pytest_asyncio.fixture
async def perf_engine(perf_config: HippoConfig) -> HippoEngine:
    eng = HippoEngine(config=perf_config)
    await eng.initialize(
        db_path=":memory:",
        owner_id="test-owner",
        conversation_id="test-session",
    )
    yield eng
    await eng.shutdown()


@pytest.mark.asyncio
async def test_pragmas_set(perf_engine: HippoEngine):
    """Verify cache_size and mmap_size pragmas are set after connection."""
    conn = perf_engine._db.conn

    async with conn.execute("PRAGMA cache_size") as cur:
        row = await cur.fetchone()
        assert row[0] == -8192

    # mmap_size PRAGMA returns empty on :memory: databases (no file to mmap).
    # We verify the pragma is set by checking it doesn't raise errors during init.
    # On file-backed DBs the value would be 268435456.


@pytest.mark.asyncio
async def test_created_at_indexes_exist(perf_engine: HippoEngine):
    """Verify performance indexes exist on messages and summaries."""
    conn = perf_engine._db.conn

    async with conn.execute(
        "SELECT name FROM sqlite_master WHERE type='index' ORDER BY name"
    ) as cur:
        rows = await cur.fetchall()
        index_names = {r[0] for r in rows}

    assert "idx_hippo_messages_created" in index_names
    assert "idx_hippo_messages_conv_created" in index_names
    assert "idx_hippo_summaries_created" in index_names
    assert "idx_hippo_summaries_conv_created" in index_names


@pytest.mark.asyncio
async def test_time_range_query_uses_index(perf_engine: HippoEngine):
    """EXPLAIN QUERY PLAN should show index scan for time-range queries."""
    conn = perf_engine._db.conn

    # Insert a test message so the table isn't empty
    await perf_engine.conversation_store.create_message(
        conversation_id=perf_engine._conversation.conversation_id,
        owner_id="test-owner",
        role="user",
        content="test",
    )

    async with conn.execute(
        "EXPLAIN QUERY PLAN SELECT * FROM hippo_messages WHERE created_at > '2026-01-01'"
    ) as cur:
        rows = await cur.fetchall()
        # Row objects — convert each column to string
        plan_text = " ".join(
            " ".join(str(col) for col in row) for row in rows
        ).lower()
        # Should use the created_at index, not a full scan
        assert "idx_hippo_messages_created" in plan_text or "index" in plan_text


@pytest.mark.asyncio
async def test_migration_creates_indexes(perf_config: HippoConfig):
    """Migration should work on a freshly created DB."""
    import aiosqlite
    from cortex.hippo.db.migrations.add_performance_indexes import (
        migrate,
        needs_migration,
    )

    conn = await aiosqlite.connect(":memory:")
    try:
        # Create minimal schema first
        await conn.executescript("""
            CREATE TABLE IF NOT EXISTS hippo_config (
                key TEXT PRIMARY KEY, value TEXT,
                updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
            );
            CREATE TABLE IF NOT EXISTS hippo_conversations (
                conversation_id INTEGER PRIMARY KEY AUTOINCREMENT,
                owner_id TEXT NOT NULL DEFAULT 'default',
                session_id TEXT NOT NULL,
                created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
                updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
            );
            CREATE TABLE IF NOT EXISTS hippo_messages (
                message_id INTEGER PRIMARY KEY AUTOINCREMENT,
                conversation_id INTEGER NOT NULL,
                owner_id TEXT NOT NULL DEFAULT 'default',
                seq INTEGER NOT NULL,
                role TEXT NOT NULL,
                content TEXT NOT NULL DEFAULT '',
                token_count INTEGER NOT NULL DEFAULT 0,
                metadata TEXT,
                created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
            );
            CREATE TABLE IF NOT EXISTS hippo_summaries (
                summary_id TEXT PRIMARY KEY,
                conversation_id INTEGER NOT NULL,
                owner_id TEXT NOT NULL DEFAULT 'default',
                kind TEXT NOT NULL,
                depth INTEGER NOT NULL DEFAULT 0,
                content TEXT NOT NULL,
                token_count INTEGER NOT NULL DEFAULT 0,
                created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
            );
        """)
        await conn.commit()

        assert await needs_migration(conn) is True
        await migrate(conn)
        assert await needs_migration(conn) is False

        # Verify indexes exist
        async with conn.execute(
            "SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_hippo_%_created%'"
        ) as cur:
            rows = await cur.fetchall()
            names = {r[0] for r in rows}

        assert "idx_hippo_messages_created" in names
        assert "idx_hippo_messages_conv_created" in names
        assert "idx_hippo_summaries_created" in names
        assert "idx_hippo_summaries_conv_created" in names
    finally:
        await conn.close()
