"""
Database schema definition and DDL operations.

This module defines the SQLite schema for the TestIO MCP persistent cache.
Schema is multi-tenant ready with customer_id isolation.

Reference: STORY-021 (Local Data Store with Incremental Sync)
"""

import logging
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    import aiosqlite

logger = logging.getLogger(__name__)

# Current schema version (increment when schema changes)
# Version 2: Added bugs table for STORY-023c
# Version 3: Added sync_events table for observability and circuit breaker
# Version 4: Added bugs_synced_at column to tests table for STORY-024
CURRENT_SCHEMA_VERSION = 4


async def get_schema_version(db: "aiosqlite.Connection") -> int:
    """Get current schema version from sync_metadata.

    Args:
        db: Active aiosqlite connection

    Returns:
        Schema version (0 if not set)
    """
    cursor = await db.execute("SELECT value FROM sync_metadata WHERE key = 'schema_version'")
    row = await cursor.fetchone()
    await cursor.close()

    if row:
        return int(row[0])
    return 0


async def set_schema_version(db: "aiosqlite.Connection", version: int) -> None:
    """Set schema version in sync_metadata.

    Args:
        db: Active aiosqlite connection
        version: Schema version to set
    """
    await db.execute(
        """
        INSERT OR REPLACE INTO sync_metadata (key, value)
        VALUES ('schema_version', ?)
        """,
        (str(version),),
    )
    await db.commit()
    logger.info(f"Schema version set to {version}")


async def check_schema_compatibility(db: "aiosqlite.Connection") -> tuple[bool, int, int]:
    """Check if current database schema is compatible.

    Args:
        db: Active aiosqlite connection

    Returns:
        Tuple of (is_compatible, current_version, expected_version)
    """
    current_version = await get_schema_version(db)
    expected_version = CURRENT_SCHEMA_VERSION

    # Compatible if versions match
    is_compatible = current_version == expected_version

    return is_compatible, current_version, expected_version


async def migrate_to_v4(db: "aiosqlite.Connection") -> None:
    """Add per-test bug sync tracking.

    Migration: Add bugs_synced_at column to tests table for intelligent
    bug caching based on test mutability.

    Args:
        db: Active aiosqlite connection
    """
    current_version = await get_schema_version(db)
    if current_version >= 4:
        return  # Already migrated

    # Check if column already exists (for new databases created with v4 schema)
    cursor = await db.execute("PRAGMA table_info(tests)")
    columns = await cursor.fetchall()
    column_names = [col[1] for col in columns]

    if "bugs_synced_at" in column_names:
        # Column already exists (new database), just update version
        await set_schema_version(db, 4)
        logger.info("Schema v4: bugs_synced_at column already exists, updated version only")
        return

    logger.info("Migrating schema from v3 to v4: Adding bugs_synced_at to tests")
    await db.execute("ALTER TABLE tests ADD COLUMN bugs_synced_at TIMESTAMP")
    await db.commit()
    await set_schema_version(db, 4)
    logger.info("Migrated to schema version 4: Added bugs_synced_at to tests")


async def initialize_schema(db: "aiosqlite.Connection") -> None:
    """Create database schema (idempotent).

    Creates tests, products, and sync_metadata tables with indexes
    for efficient querying. All tables include customer_id for multi-tenant isolation.

    Args:
        db: Active aiosqlite connection
    """
    # Tests table with customer_id for multi-tenant isolation
    await db.execute(
        """
        CREATE TABLE IF NOT EXISTS tests (
            id INTEGER PRIMARY KEY,
            customer_id INTEGER NOT NULL,
            product_id INTEGER NOT NULL,
            data JSON NOT NULL,
            status TEXT NOT NULL,
            created_at TIMESTAMP,
            start_at TIMESTAMP,
            end_at TIMESTAMP,
            synced_at TIMESTAMP,
            bugs_synced_at TIMESTAMP
        )
        """
    )

    # Create indexes for efficient filtering
    await db.execute(
        """
        CREATE INDEX IF NOT EXISTS idx_customer_product_status
        ON tests (customer_id, product_id, status)
        """
    )
    await db.execute(
        """
        CREATE INDEX IF NOT EXISTS idx_customer_product_created
        ON tests (customer_id, product_id, created_at)
        """
    )
    await db.execute(
        """
        CREATE INDEX IF NOT EXISTS idx_customer_product_start
        ON tests (customer_id, product_id, start_at)
        """
    )
    await db.execute(
        """
        CREATE INDEX IF NOT EXISTS idx_customer_product_end
        ON tests (customer_id, product_id, end_at)
        """
    )

    # Products table with customer_id
    await db.execute(
        """
        CREATE TABLE IF NOT EXISTS products (
            id INTEGER PRIMARY KEY,
            customer_id INTEGER NOT NULL,
            data JSON NOT NULL,
            last_synced TIMESTAMP
        )
        """
    )

    # Create index for customer filtering
    await db.execute(
        """
        CREATE INDEX IF NOT EXISTS idx_customer
        ON products (customer_id)
        """
    )

    # Sync metadata table (for tracking problematic tests, schema version, etc.)
    await db.execute(
        """
        CREATE TABLE IF NOT EXISTS sync_metadata (
            key TEXT PRIMARY KEY,
            value JSON
        )
        """
    )

    # Bugs table (STORY-023c) - Always fresh from API, no last_synced needed
    await db.execute(
        """
        CREATE TABLE IF NOT EXISTS bugs (
            id INTEGER PRIMARY KEY,
            customer_id INTEGER NOT NULL,
            test_id INTEGER NOT NULL,
            title TEXT NOT NULL,
            severity TEXT,
            status TEXT,
            acceptance_state TEXT,
            created_at TEXT,
            raw_data TEXT NOT NULL,
            synced_at TIMESTAMP,
            FOREIGN KEY (test_id) REFERENCES tests(id)
        )
        """
    )

    # Create index for efficient bug queries by test_id
    await db.execute(
        """
        CREATE INDEX IF NOT EXISTS idx_bugs_test_id
        ON bugs (test_id, customer_id)
        """
    )

    # Sync events table for observability and circuit breaker (Version 3)
    await db.execute(
        """
        CREATE TABLE IF NOT EXISTS sync_events (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            event_type TEXT NOT NULL,
            started_at TEXT NOT NULL,
            completed_at TEXT,
            status TEXT NOT NULL,
            products_synced INTEGER,
            tests_discovered INTEGER,
            tests_refreshed INTEGER,
            duration_seconds REAL,
            error_message TEXT,
            trigger_source TEXT
        )
        """
    )

    # Create index for efficient queries by status and time
    await db.execute(
        """
        CREATE INDEX IF NOT EXISTS idx_sync_events_status_time
        ON sync_events (status, started_at DESC)
        """
    )

    await db.commit()

    # Get current version BEFORE applying migrations
    current_version = await get_schema_version(db)

    # For brand new databases (version 0), all columns already created
    if current_version == 0:
        # Tables already created with all v4 columns above
        await set_schema_version(db, CURRENT_SCHEMA_VERSION)
    # Run migrations sequentially for existing databases
    elif current_version < 4:
        await migrate_to_v4(db)
        # migrate_to_v4 sets version to 4 internally

    logger.info(f"Database schema initialized successfully (version {CURRENT_SCHEMA_VERSION})")


async def vacuum_database(db: "aiosqlite.Connection") -> None:
    """Compact database and reclaim space.

    Args:
        db: Active aiosqlite connection
    """
    await db.execute("VACUUM")
    await db.commit()
    logger.debug("Database vacuumed successfully")


async def configure_wal_mode(db: "aiosqlite.Connection") -> None:
    """Configure Write-Ahead Logging for concurrent reads.

    WAL mode allows background writes without blocking read queries.
    Also configures checkpointing and busy timeout.

    Args:
        db: Active aiosqlite connection
    """
    # Enable WAL mode for concurrent reads
    await db.execute("PRAGMA journal_mode=WAL")

    # WAL checkpointing configuration (prevent disk bloat)
    # Checkpoint after 1000 pages (~4MB)
    await db.execute("PRAGMA wal_autocheckpoint=1000")

    # Wait 5 seconds before failing on lock
    await db.execute("PRAGMA busy_timeout=5000")

    logger.debug("WAL mode configured successfully")
