"""Main VibeDB database class - the entry point for all operations."""

from typing import Dict, List, Optional, Any

from vibedb.storage.engine import StorageEngine
from vibedb.core import schema
from vibedb.core.collection import Collection
from vibedb.errors import DatabaseError


class VibeDB:
    """
    Main database class for VibeDB.

    This is the entry point for all database operations. It manages the database
    connection, collections, and global configuration.

    Example:
        >>> db = VibeDB("app.db")
        >>> users = db.collection("users")
        >>> users.insert({"name": "Alice", "age": 28})
        >>> db.close()

    Can also be used as a context manager:
        >>> with VibeDB("app.db") as db:
        ...     users = db.collection("users")
        ...     users.insert({"name": "Alice"})
    """

    def __init__(
        self,
        path: str = ":memory:",
        auto_index_hints: bool = True,
        log_slow_queries: bool = True,
        slow_query_threshold_ms: int = 100,
        timeout: float = 5.0
    ):
        """
        Initialize VibeDB database.

        Args:
            path: Database file path or ":memory:" for in-memory database
            auto_index_hints: Enable automatic index suggestions based on slow queries
            log_slow_queries: Log queries that exceed threshold
            slow_query_threshold_ms: Threshold in milliseconds for slow query logging
            timeout: Database lock timeout in seconds

        Raises:
            DatabaseError: If database initialization fails

        Example:
            >>> # File-based database
            >>> db = VibeDB("myapp.db")
            >>>
            >>> # In-memory database (for testing)
            >>> db = VibeDB(":memory:")
            >>>
            >>> # Custom configuration
            >>> db = VibeDB("app.db", slow_query_threshold_ms=200)
        """
        self.path = path
        self.auto_index_hints = auto_index_hints
        self.log_slow_queries = log_slow_queries
        self.slow_query_threshold_ms = slow_query_threshold_ms

        # Initialize storage engine
        self._engine = StorageEngine(path=path, timeout=timeout)

        # Initialize database schema
        schema.init_database_schema(self._engine)

        # Cache for collection instances
        self._collections: Dict[str, Collection] = {}

    @property
    def engine(self) -> StorageEngine:
        """Get the underlying storage engine."""
        return self._engine

    def collection(self, name: str) -> Collection:
        """
        Get or create a collection.

        Collections are created automatically when first accessed.

        Args:
            name: Collection name

        Returns:
            Collection: Collection instance

        Example:
            >>> db = VibeDB("app.db")
            >>> users = db.collection("users")
            >>> posts = db.collection("posts")
        """
        # Return cached collection if exists
        if name in self._collections:
            return self._collections[name]

        # Create collection table if it doesn't exist
        if not schema.collection_exists(self._engine, name):
            schema.create_collection_table(self._engine, name)

        # Create and cache collection instance
        from vibedb.core.collection import Collection
        collection = Collection(self, name)
        self._collections[name] = collection

        return collection

    def collections(self) -> List[str]:
        """
        List all collection names in the database.

        Returns:
            list[str]: List of collection names

        Example:
            >>> db = VibeDB("app.db")
            >>> db.collection("users")
            >>> db.collection("posts")
            >>> db.collections()
            ['posts', 'users']
        """
        return schema.list_collections(self._engine)

    def drop_collection(self, name: str) -> bool:
        """
        Delete a collection and all its documents.

        Args:
            name: Collection name

        Returns:
            bool: True if collection was dropped, False if it didn't exist

        Example:
            >>> db = VibeDB("app.db")
            >>> db.drop_collection("old_collection")
            True
        """
        if not schema.collection_exists(self._engine, name):
            return False

        # Remove from cache
        if name in self._collections:
            del self._collections[name]

        # Drop table and metadata
        schema.drop_collection_table(self._engine, name)

        return True

    def collection_info(self, name: str) -> Optional[Dict[str, Any]]:
        """
        Get metadata about a collection.

        Args:
            name: Collection name

        Returns:
            dict: Collection metadata or None if not found

        Example:
            >>> db = VibeDB("app.db")
            >>> info = db.collection_info("users")
            >>> print(info['document_count'])
            42
        """
        return schema.get_collection_info(self._engine, name)

    def stats(self) -> Dict[str, Any]:
        """
        Get database statistics.

        Returns:
            dict: Database statistics including size, collection count, etc.

        Example:
            >>> db = VibeDB("app.db")
            >>> stats = db.stats()
            >>> print(f"Database size: {stats['size_mb']} MB")
            >>> print(f"Collections: {stats['collection_count']}")
        """
        # Get storage engine stats
        stats = self._engine.get_stats()

        # Add VibeDB-specific stats
        stats['collection_count'] = len(self.collections())
        stats['path'] = self.path

        # Add total document count
        total_docs = 0
        for coll_name in self.collections():
            info = self.collection_info(coll_name)
            if info:
                total_docs += info.get('document_count', 0)
        stats['total_documents'] = total_docs

        return stats

    def close(self):
        """
        Close the database connection.

        Should be called when done with the database to free resources.

        Example:
            >>> db = VibeDB("app.db")
            >>> # ... do work ...
            >>> db.close()
        """
        if self._engine:
            self._engine.close()

    def vacuum(self):
        """
        Optimize database by rebuilding it.

        This reclaims unused space and can improve performance.
        Recommended to run periodically on production databases.

        Example:
            >>> db = VibeDB("app.db")
            >>> db.vacuum()  # Reclaim unused space
        """
        self._engine.vacuum()

    def studio(self, port: int = 5000, host: str = "127.0.0.1"):
        """
        Launch Studio web UI for browsing and managing the database.

        Requires Flask to be installed (pip install vibedb[studio]).

        Args:
            port: Port to run web server on (default: 5000)
            host: Host to bind to (default: 127.0.0.1)

        Raises:
            ImportError: If Flask is not installed

        Example:
            >>> db = VibeDB("app.db")
            >>> db.studio(port=5000)  # Opens http://localhost:5000
        """
        try:
            from vibedb.studio.app import launch_studio
            launch_studio(self, host=host, port=port)
        except ImportError:
            raise ImportError(
                "Studio requires Flask. Install with: pip install vibedb[studio]"
            )

    def __enter__(self):
        """Context manager entry."""
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit - closes database."""
        self.close()

    def __repr__(self) -> str:
        """String representation."""
        return f"VibeDB(path='{self.path}', collections={len(self.collections())})"
