"""Tests for schema migration system."""

import sqlite3
from pathlib import Path

from memotrail.storage.migrations import Migrator, MIGRATIONS


def _make_db(tmp_path: Path) -> sqlite3.Connection:
    """Create a fresh SQLite connection."""
    conn = sqlite3.connect(str(tmp_path / "test.db"))
    conn.row_factory = sqlite3.Row
    return conn


class TestMigrator:
    def test_creates_migration_table(self, tmp_path):
        conn = _make_db(tmp_path)
        migrator = Migrator(conn)
        # Should have schema_version table
        row = conn.execute(
            "SELECT name FROM sqlite_master WHERE type='table' AND name='schema_version'"
        ).fetchone()
        assert row is not None

    def test_initial_version_is_zero(self, tmp_path):
        conn = _make_db(tmp_path)
        migrator = Migrator(conn)
        assert migrator.get_current_version() == 0

    def test_target_version(self, tmp_path):
        conn = _make_db(tmp_path)
        migrator = Migrator(conn)
        assert migrator.get_target_version() == len(MIGRATIONS)

    def test_migrate_from_scratch(self, tmp_path):
        conn = _make_db(tmp_path)
        # Create base tables first (simulating SQLiteStore init)
        conn.executescript("""
            CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY, project TEXT, started_at TEXT NOT NULL,
                ended_at TEXT, summary TEXT, message_count INTEGER DEFAULT 0, tags TEXT DEFAULT '[]', source TEXT DEFAULT 'claude_code');
            CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY, session_id TEXT, role TEXT, content TEXT, timestamp TEXT, token_count INTEGER);
            CREATE TABLE IF NOT EXISTS decisions (id TEXT PRIMARY KEY, session_id TEXT, decision_text TEXT, context TEXT, category TEXT, created_at TEXT);
            CREATE TABLE IF NOT EXISTS memories (id TEXT PRIMARY KEY, content TEXT, tags TEXT DEFAULT '[]', created_at TEXT, updated_at TEXT);
        """)

        migrator = Migrator(conn)
        applied = migrator.migrate()
        assert len(applied) > 0
        assert migrator.get_current_version() == migrator.get_target_version()

    def test_idempotent_migration(self, tmp_path):
        conn = _make_db(tmp_path)
        conn.executescript("""
            CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY, project TEXT, started_at TEXT NOT NULL,
                ended_at TEXT, summary TEXT, message_count INTEGER DEFAULT 0, tags TEXT DEFAULT '[]', source TEXT DEFAULT 'claude_code');
            CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY, session_id TEXT, role TEXT, content TEXT, timestamp TEXT, token_count INTEGER);
            CREATE TABLE IF NOT EXISTS decisions (id TEXT PRIMARY KEY, session_id TEXT, decision_text TEXT, context TEXT, category TEXT, created_at TEXT);
            CREATE TABLE IF NOT EXISTS memories (id TEXT PRIMARY KEY, content TEXT, tags TEXT DEFAULT '[]', created_at TEXT, updated_at TEXT);
        """)

        migrator = Migrator(conn)
        applied1 = migrator.migrate()
        applied2 = migrator.migrate()
        assert len(applied2) == 0  # All already applied

    def test_get_applied_migrations(self, tmp_path):
        conn = _make_db(tmp_path)
        conn.executescript("""
            CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY, project TEXT, started_at TEXT NOT NULL,
                ended_at TEXT, summary TEXT, message_count INTEGER DEFAULT 0, tags TEXT DEFAULT '[]', source TEXT DEFAULT 'claude_code');
            CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY, session_id TEXT, role TEXT, content TEXT, timestamp TEXT, token_count INTEGER);
            CREATE TABLE IF NOT EXISTS decisions (id TEXT PRIMARY KEY, session_id TEXT, decision_text TEXT, context TEXT, category TEXT, created_at TEXT);
            CREATE TABLE IF NOT EXISTS memories (id TEXT PRIMARY KEY, content TEXT, tags TEXT DEFAULT '[]', created_at TEXT, updated_at TEXT);
        """)

        migrator = Migrator(conn)
        migrator.migrate()

        applied = migrator.get_applied_migrations()
        assert len(applied) > 0
        assert all("version" in m for m in applied)
        assert all("applied_at" in m for m in applied)

    def test_entities_table_created(self, tmp_path):
        conn = _make_db(tmp_path)
        conn.executescript("""
            CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY, project TEXT, started_at TEXT NOT NULL,
                ended_at TEXT, summary TEXT, message_count INTEGER DEFAULT 0, tags TEXT DEFAULT '[]', source TEXT DEFAULT 'claude_code');
            CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY, session_id TEXT, role TEXT, content TEXT, timestamp TEXT, token_count INTEGER);
            CREATE TABLE IF NOT EXISTS decisions (id TEXT PRIMARY KEY, session_id TEXT, decision_text TEXT, context TEXT, category TEXT, created_at TEXT);
            CREATE TABLE IF NOT EXISTS memories (id TEXT PRIMARY KEY, content TEXT, tags TEXT DEFAULT '[]', created_at TEXT, updated_at TEXT);
        """)

        migrator = Migrator(conn)
        migrator.migrate()

        # Verify entities table exists
        row = conn.execute(
            "SELECT name FROM sqlite_master WHERE type='table' AND name='entities'"
        ).fetchone()
        assert row is not None

    def test_fact_history_table_created(self, tmp_path):
        conn = _make_db(tmp_path)
        conn.executescript("""
            CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY, project TEXT, started_at TEXT NOT NULL,
                ended_at TEXT, summary TEXT, message_count INTEGER DEFAULT 0, tags TEXT DEFAULT '[]', source TEXT DEFAULT 'claude_code');
            CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY, session_id TEXT, role TEXT, content TEXT, timestamp TEXT, token_count INTEGER);
            CREATE TABLE IF NOT EXISTS decisions (id TEXT PRIMARY KEY, session_id TEXT, decision_text TEXT, context TEXT, category TEXT, created_at TEXT);
            CREATE TABLE IF NOT EXISTS memories (id TEXT PRIMARY KEY, content TEXT, tags TEXT DEFAULT '[]', created_at TEXT, updated_at TEXT);
        """)

        migrator = Migrator(conn)
        migrator.migrate()

        row = conn.execute(
            "SELECT name FROM sqlite_master WHERE type='table' AND name='fact_history'"
        ).fetchone()
        assert row is not None

    def test_migrations_ordered(self):
        """Verify migrations have sequential version numbers."""
        versions = [m[0] for m in MIGRATIONS]
        assert versions == sorted(versions)
        assert len(versions) == len(set(versions))  # No duplicates
