"""Slow query analyzer for VibeDB - tracks and analyzes query performance."""

import time
from typing import Dict, List, Any, Optional, TYPE_CHECKING
import json

from vibedb.utils import current_timestamp

if TYPE_CHECKING:
    from vibedb.core.collection import Collection


class SlowQueryAnalyzer:
    """
    Analyzes query performance and logs slow queries.

    Tracks queries that exceed the configured threshold and provides
    data for index suggestions.

    Example:
        >>> analyzer = SlowQueryAnalyzer(collection, threshold_ms=100)
        >>> with analyzer.measure(query_dict):
        ...     # Execute query
        ...     results = execute_query()
        >>> # Slow query is automatically logged if execution time > threshold
    """

    def __init__(self, collection: "Collection", threshold_ms: float = 100):
        """
        Initialize slow query analyzer.

        Args:
            collection: Collection to analyze
            threshold_ms: Threshold in milliseconds for slow queries
        """
        self.collection = collection
        self.db = collection.database
        self.threshold_ms = threshold_ms
        self._current_query = None
        self._start_time = None

    def log_query(
        self,
        query: Dict,
        execution_time_ms: float,
        suggested_indexes: Optional[List[str]] = None
    ):
        """
        Log a slow query to the database.

        Args:
            query: Query dict
            execution_time_ms: Execution time in milliseconds
            suggested_indexes: Optional list of suggested index fields

        Example:
            >>> analyzer.log_query(
            ...     {"age": {"$gte": 25}},
            ...     250.5,
            ...     suggested_indexes=[["age"]]
            ... )
        """
        # Only log if above threshold
        if execution_time_ms < self.threshold_ms:
            return

        sql = """
            INSERT INTO _vibedb_slow_queries
            (collection, query, execution_time_ms, timestamp, suggested_indexes)
            VALUES (?, ?, ?, ?, ?)
        """

        self.db.engine.execute(
            sql,
            (
                self.collection.name,
                json.dumps(query),
                execution_time_ms,
                current_timestamp(),
                json.dumps(suggested_indexes) if suggested_indexes else None
            )
        )
        self.db.engine.commit()

    def measure(self, query: Dict):
        """
        Context manager to measure query execution time.

        Args:
            query: Query dict being executed

        Yields:
            SlowQueryAnalyzer: self

        Example:
            >>> with analyzer.measure({"age": {"$gte": 25}}):
            ...     results = collection.find(query).to_list()
        """
        return QueryTimer(self, query)

    def get_slow_queries(
        self,
        limit: int = 100,
        min_execution_time: float = None
    ) -> List[Dict[str, Any]]:
        """
        Get recent slow queries.

        Args:
            limit: Maximum number of queries to return
            min_execution_time: Minimum execution time filter (ms)

        Returns:
            list[dict]: List of slow query records

        Example:
            >>> slow = analyzer.get_slow_queries(limit=20, min_execution_time=200)
            >>> for q in slow:
            ...     print(f"{q['execution_time_ms']}ms: {q['query']}")
        """
        sql = """
            SELECT id, query, execution_time_ms, timestamp, suggested_indexes
            FROM _vibedb_slow_queries
            WHERE collection = ?
        """
        params = [self.collection.name]

        if min_execution_time is not None:
            sql += " AND execution_time_ms >= ?"
            params.append(min_execution_time)

        sql += " ORDER BY timestamp DESC LIMIT ?"
        params.append(limit)

        rows = self.db.engine.execute(sql, tuple(params), fetch='all')

        results = []
        for row in rows:
            results.append({
                'id': row['id'],
                'query': json.loads(row['query']),
                'execution_time_ms': row['execution_time_ms'],
                'timestamp': row['timestamp'],
                'suggested_indexes': json.loads(row['suggested_indexes']) if row['suggested_indexes'] else None
            })

        return results

    def get_query_stats(self) -> Dict[str, Any]:
        """
        Get statistics about slow queries.

        Returns:
            dict: Statistics including count, avg time, most common fields

        Example:
            >>> stats = analyzer.get_query_stats()
            >>> print(f"Total slow queries: {stats['total_count']}")
            >>> print(f"Average time: {stats['avg_execution_time_ms']}ms")
        """
        # Get basic stats
        sql = """
            SELECT
                COUNT(*) as count,
                AVG(execution_time_ms) as avg_time,
                MAX(execution_time_ms) as max_time,
                MIN(execution_time_ms) as min_time
            FROM _vibedb_slow_queries
            WHERE collection = ?
        """

        result = self.db.engine.execute(
            sql,
            (self.collection.name,),
            fetch='one'
        )

        stats = {
            'total_count': result['count'] if result else 0,
            'avg_execution_time_ms': round(result['avg_time'], 2) if result and result['avg_time'] else 0,
            'max_execution_time_ms': result['max_time'] if result else 0,
            'min_execution_time_ms': result['min_time'] if result else 0,
        }

        # Analyze queried fields
        stats['most_queried_fields'] = self._analyze_queried_fields()

        return stats

    def clear_slow_queries(self, older_than_ms: int = None) -> int:
        """
        Clear slow query log.

        Args:
            older_than_ms: Only clear queries older than this many milliseconds

        Returns:
            int: Number of queries cleared

        Example:
            >>> # Clear all
            >>> analyzer.clear_slow_queries()
            >>>
            >>> # Clear queries older than 1 hour
            >>> analyzer.clear_slow_queries(older_than_ms=3600000)
        """
        if older_than_ms is None:
            # Clear all for this collection
            sql = "DELETE FROM _vibedb_slow_queries WHERE collection = ?"
            params = (self.collection.name,)
        else:
            # Clear old queries
            cutoff_time = current_timestamp() - older_than_ms
            sql = "DELETE FROM _vibedb_slow_queries WHERE collection = ? AND timestamp < ?"
            params = (self.collection.name, cutoff_time)

        cursor = self.db.engine.execute(sql, params)
        deleted_count = cursor.rowcount
        self.db.engine.commit()

        return deleted_count

    def _analyze_queried_fields(self) -> List[Dict[str, Any]]:
        """
        Analyze which fields are most frequently queried.

        Returns:
            list[dict]: List of {field, count, avg_time}
        """
        # Get all slow queries
        queries = self.get_slow_queries(limit=1000)

        # Count field usage
        field_stats = {}

        for query_record in queries:
            query = query_record['query']
            exec_time = query_record['execution_time_ms']

            # Extract fields from query
            fields = self._extract_query_fields(query)

            for field in fields:
                if field not in field_stats:
                    field_stats[field] = {'count': 0, 'total_time': 0}

                field_stats[field]['count'] += 1
                field_stats[field]['total_time'] += exec_time

        # Convert to list with averages
        results = []
        for field, stats in field_stats.items():
            results.append({
                'field': field,
                'query_count': stats['count'],
                'avg_execution_time_ms': round(stats['total_time'] / stats['count'], 2)
            })

        # Sort by query count descending
        results.sort(key=lambda x: x['query_count'], reverse=True)

        return results[:10]  # Top 10

    def _extract_query_fields(self, query: Dict, prefix: str = "") -> List[str]:
        """
        Extract field names from a query dict.

        Args:
            query: Query dict
            prefix: Prefix for nested fields

        Returns:
            list[str]: List of field names

        Example:
            >>> _extract_query_fields({"age": {"$gte": 25}, "status": "active"})
            ['age', 'status']
            >>> _extract_query_fields({"$and": [{"age": 25}, {"name": "Alice"}]})
            ['age', 'name']
        """
        fields = []

        for key, value in query.items():
            if key.startswith('$'):
                # Logical operator
                if key in ('$and', '$or') and isinstance(value, list):
                    # Recursively extract from sub-queries
                    for sub_query in value:
                        fields.extend(self._extract_query_fields(sub_query, prefix))
                elif key == '$not' and isinstance(value, dict):
                    fields.extend(self._extract_query_fields(value, prefix))
                # Skip other operators like $eq, $gte, etc.
            else:
                # Field name
                full_field = f"{prefix}{key}" if prefix else key
                fields.append(full_field)

                # Check for nested queries
                if isinstance(value, dict) and not any(k.startswith('$') for k in value.keys()):
                    # Nested object, recurse
                    fields.extend(self._extract_query_fields(value, f"{full_field}."))

        return fields


class QueryTimer:
    """
    Context manager for timing query execution.

    Example:
        >>> with QueryTimer(analyzer, query_dict):
        ...     results = execute_query()
    """

    def __init__(self, analyzer: SlowQueryAnalyzer, query: Dict):
        """
        Initialize query timer.

        Args:
            analyzer: SlowQueryAnalyzer instance
            query: Query being timed
        """
        self.analyzer = analyzer
        self.query = query
        self.start_time = None
        self.execution_time_ms = None

    def __enter__(self):
        """Start timing."""
        self.start_time = time.perf_counter()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """Stop timing and log if slow."""
        if self.start_time is not None:
            elapsed = time.perf_counter() - self.start_time
            self.execution_time_ms = elapsed * 1000  # Convert to milliseconds

            # Log if slow
            if self.execution_time_ms >= self.analyzer.threshold_ms:
                self.analyzer.log_query(self.query, self.execution_time_ms)

        return False  # Don't suppress exceptions
