"""Index suggestion engine for VibeDB - intelligent index recommendations."""

from typing import List, Dict, Any, TYPE_CHECKING

if TYPE_CHECKING:
    from vibedb.core.collection import Collection


class IndexSuggestionEngine:
    """
    Generates intelligent index suggestions based on query patterns.

    Analyzes slow queries to identify fields that would benefit from indexing.
    Provides estimated performance improvements.

    Example:
        >>> engine = IndexSuggestionEngine(collection)
        >>> suggestions = engine.generate_suggestions()
        >>> for s in suggestions:
        ...     print(f"Create index on {s['fields']}: {s['reason']}")
        ...     print(f"Expected speedup: {s['estimated_speedup']}")
    """

    # Thresholds for suggestions
    MIN_QUERY_COUNT = 3  # Minimum times field must be queried
    MIN_AVG_TIME_MS = 50  # Minimum average execution time (ms)

    def __init__(self, collection: "Collection"):
        """
        Initialize suggestion engine.

        Args:
            collection: Collection to generate suggestions for
        """
        self.collection = collection

    def generate_suggestions(
        self,
        min_query_count: int = None,
        min_avg_time_ms: float = None,
        max_suggestions: int = 10
    ) -> List[Dict[str, Any]]:
        """
        Generate index suggestions based on slow query analysis.

        Args:
            min_query_count: Minimum query count (default: 3)
            min_avg_time_ms: Minimum average time (default: 50ms)
            max_suggestions: Maximum suggestions to return

        Returns:
            list[dict]: List of index suggestions

        Example:
            >>> suggestions = engine.generate_suggestions()
            >>> for s in suggestions:
            ...     print(f"{s['fields']}: {s['reason']}")
            ...     # Apply suggestion
            ...     collection.create_index(s['fields'])
        """
        min_query_count = min_query_count or self.MIN_QUERY_COUNT
        min_avg_time_ms = min_avg_time_ms or self.MIN_AVG_TIME_MS

        # Get query statistics from analyzer
        from vibedb.indexes.analyzer import SlowQueryAnalyzer

        analyzer = SlowQueryAnalyzer(
            self.collection,
            threshold_ms=self.collection.database.slow_query_threshold_ms
        )

        stats = analyzer.get_query_stats()
        most_queried = stats.get('most_queried_fields', [])

        # Get existing indexes
        from vibedb.indexes.manager import IndexManager
        manager = IndexManager(self.collection)
        existing_indexes = manager.list_indexes()
        existing_fields = set()
        for idx in existing_indexes:
            existing_fields.update(idx['fields'])

        # Generate suggestions
        suggestions = []

        for field_stat in most_queried:
            field = field_stat['field']
            count = field_stat['query_count']
            avg_time = field_stat['avg_execution_time_ms']

            # Skip if below thresholds
            if count < min_query_count or avg_time < min_avg_time_ms:
                continue

            # Skip if already indexed
            if field in existing_fields:
                continue

            # Calculate estimated speedup
            speedup = self._estimate_speedup(count, avg_time)

            # Create suggestion
            suggestion = {
                'fields': [field],
                'reason': f"Field '{field}' queried {count} times with avg time {avg_time:.1f}ms",
                'query_count': count,
                'avg_execution_time_ms': avg_time,
                'estimated_speedup': speedup,
                'priority': self._calculate_priority(count, avg_time)
            }

            suggestions.append(suggestion)

        # Sort by priority (highest first)
        suggestions.sort(key=lambda s: s['priority'], reverse=True)

        # Return top suggestions
        return suggestions[:max_suggestions]

    def explain_suggestion(self, suggestion: Dict[str, Any]) -> str:
        """
        Generate human-readable explanation for a suggestion.

        Args:
            suggestion: Suggestion dict

        Returns:
            str: Explanation text

        Example:
            >>> suggestion = suggestions[0]
            >>> print(engine.explain_suggestion(suggestion))
            Field 'age' is queried 47 times with average execution time 234ms.
            Creating an index could improve query speed by 10-100x.
            Run: collection.create_index(['age'])
        """
        fields = suggestion['fields']
        count = suggestion['query_count']
        avg_time = suggestion['avg_execution_time_ms']
        speedup = suggestion['estimated_speedup']

        explanation = f"Field '{fields[0]}' is queried {count} times "
        explanation += f"with average execution time {avg_time:.1f}ms.\n"
        explanation += f"Creating an index could improve query speed by {speedup}.\n"
        explanation += f"Run: collection.create_index({fields})"

        return explanation

    def auto_create_indexes(
        self,
        min_priority: float = 5.0,
        max_indexes: int = 5,
        dry_run: bool = False
    ) -> List[Dict[str, Any]]:
        """
        Automatically create suggested indexes.

        Args:
            min_priority: Minimum priority score to auto-create
            max_indexes: Maximum indexes to create
            dry_run: If True, only return what would be created

        Returns:
            list[dict]: List of created (or would-be-created) indexes

        Example:
            >>> # Preview what would be created
            >>> preview = engine.auto_create_indexes(dry_run=True)
            >>> for idx in preview:
            ...     print(f"Would create: {idx['fields']}")
            >>>
            >>> # Actually create indexes
            >>> created = engine.auto_create_indexes()
        """
        suggestions = self.generate_suggestions()

        # Filter by priority
        high_priority = [
            s for s in suggestions
            if s['priority'] >= min_priority
        ][:max_indexes]

        created = []

        for suggestion in high_priority:
            fields = suggestion['fields']

            if dry_run:
                created.append({
                    'fields': fields,
                    'reason': suggestion['reason'],
                    'dry_run': True
                })
            else:
                # Create the index
                from vibedb.indexes.manager import IndexManager
                manager = IndexManager(self.collection)

                try:
                    index_id = manager.create_index(fields)
                    created.append({
                        'index_id': index_id,
                        'fields': fields,
                        'reason': suggestion['reason']
                    })
                except Exception as e:
                    # Skip if creation fails
                    created.append({
                        'fields': fields,
                        'error': str(e),
                        'failed': True
                    })

        return created

    # ==================== Private Methods ====================

    def _estimate_speedup(self, query_count: int, avg_time_ms: float) -> str:
        """
        Estimate potential speedup from creating an index.

        Args:
            query_count: Number of times field was queried
            avg_time_ms: Average execution time

        Returns:
            str: Human-readable speedup estimate

        Example:
            >>> _estimate_speedup(50, 200)
            '10-100x'
            >>> _estimate_speedup(5, 60)
            '5-10x'
        """
        # Simple heuristic based on time
        if avg_time_ms > 500:
            return "10-100x"
        elif avg_time_ms > 200:
            return "5-20x"
        elif avg_time_ms > 100:
            return "3-10x"
        else:
            return "2-5x"

    def _calculate_priority(self, query_count: int, avg_time_ms: float) -> float:
        """
        Calculate priority score for a suggestion.

        Higher score = more important to create index.

        Args:
            query_count: Number of times field was queried
            avg_time_ms: Average execution time

        Returns:
            float: Priority score (0-100)

        Formula: (query_count * avg_time_ms) / 1000
        This balances frequency and execution time.
        """
        # Normalize: queries that are both frequent and slow get highest priority
        score = (query_count * avg_time_ms) / 100

        # Cap at 100
        return min(score, 100.0)


def suggest_indexes_for_query(query: Dict, existing_indexes: List[Dict]) -> List[str]:
    """
    Suggest indexes for a specific query.

    Analyzes a query and suggests which fields should be indexed.

    Args:
        query: Query dict
        existing_indexes: List of existing index metadata

    Returns:
        list[str]: List of field names that should be indexed

    Example:
        >>> query = {"age": {"$gte": 25}, "status": "active"}
        >>> suggestions = suggest_indexes_for_query(query, [])
        >>> print(suggestions)
        ['age', 'status']
    """
    # Extract fields from query
    fields = _extract_fields_from_query(query)

    # Get existing indexed fields
    existing_fields = set()
    for idx in existing_indexes:
        existing_fields.update(idx['fields'])

    # Suggest fields that aren't indexed
    suggestions = [f for f in fields if f not in existing_fields]

    return suggestions


def _extract_fields_from_query(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
    """
    fields = []

    for key, value in query.items():
        if key.startswith('$'):
            # Logical operator
            if key in ('$and', '$or') and isinstance(value, list):
                for sub_query in value:
                    fields.extend(_extract_fields_from_query(sub_query, prefix))
            elif key == '$not' and isinstance(value, dict):
                fields.extend(_extract_fields_from_query(value, prefix))
        else:
            # Field name
            full_field = f"{prefix}{key}" if prefix else key
            fields.append(full_field)

            # Check for nested queries (excluding operator dicts)
            if isinstance(value, dict) and not any(k.startswith('$') for k in value.keys()):
                fields.extend(_extract_fields_from_query(value, f"{full_field}."))

    return list(set(fields))  # Remove duplicates
