"""Direct read-only connection to tenant Aurora PostgreSQL databases.

Used in hybrid mode for low-latency reads (agent memory, conversation
history) while mutations go through the platform REST API.

Connects to {tenant_id}_db.aivibe.cloud:5432 using asyncpg.
"""

from __future__ import annotations

from typing import Any

try:
    import asyncpg  # type: ignore[import-untyped]  # asyncpg has no type stubs
except ImportError:
    asyncpg = None

from aicippy.utils.logging import get_logger

logger = get_logger(__name__)


class TenantDBReader:
    """Direct read-only connection to a tenant's Aurora PostgreSQL database.

    Used for low-latency reads (agent memory, conversation history)
    while mutations go through the API. Connection pooling via asyncpg.
    """

    __slots__ = (
        "_credentials",
        "_host",
        "_max_pool_size",
        "_min_pool_size",
        "_pool",
        "_port",
        "_ssl",
        "_tenant_id",
    )

    def __init__(
        self,
        tenant_id: str,
        db_credentials: dict[str, str],
        db_host_suffix: str = "_db.aivibe.cloud",
        ssl: bool = True,
        **pool_kwargs: int,
    ) -> None:
        """Initialize the TenantDBReader.

        Args:
            tenant_id: Tenant identifier (used to derive the DB host).
            db_credentials: Dict with keys: username, password, database.
            db_host_suffix: Domain suffix for the DB host (default: _db.aivibe.cloud).
            ssl: Whether to use SSL (default: True).
            **pool_kwargs: Additional int arguments like port, min_pool_size, max_pool_size.

        """
        self._tenant_id = tenant_id
        self._host = f"{tenant_id}{db_host_suffix}"
        self._port = pool_kwargs.get("port", 5432)
        self._ssl = ssl
        self._credentials = db_credentials
        self._min_pool_size = pool_kwargs.get("min_pool_size", 1)
        self._max_pool_size = pool_kwargs.get("max_pool_size", 5)
        self._pool: asyncpg.Pool | None = None  # lazy initialized

    async def _ensure_pool(self) -> asyncpg.Pool:
        """Create the connection pool if not already created."""
        if self._pool is not None:
            return self._pool

        if asyncpg is None:
            logger.warning("asyncpg_not_installed")
            msg = "asyncpg is not installed. Run 'pip install asyncpg' to enable direct DB reads."
            raise ImportError(msg)

        try:
            ssl_context: object = "require" if self._ssl else False

            self._pool = await asyncpg.create_pool(
                host=self._host,
                port=self._port,
                user=self._credentials.get("username", ""),
                password=self._credentials.get("password", ""),
                database=self._credentials.get("database", "aicippy"),
                ssl=ssl_context,
                min_size=self._min_pool_size,
                max_size=self._max_pool_size,
                command_timeout=10,
            )

        except Exception as e:
            logger.warning(
                "tenant_db_pool_creation_failed",
                tenant_id=self._tenant_id,
                error=str(e),
            )
            raise
        else:
            logger.info(
                "tenant_db_pool_created",
                tenant_id=self._tenant_id,
                host=self._host,
            )
            return self._pool

    async def get_conversation_history(
        self,
        user_id: str,
        limit: int = 50,
    ) -> list[dict[str, Any]]:
        """Read conversation history directly from the tenant database.

        Args:
            user_id: User identifier.
            limit: Maximum number of conversations to return.

        Returns:
            List of conversation records.

        """
        pool = await self._ensure_pool()
        rows = await pool.fetch(
            """
            SELECT session_id, messages, created_at, updated_at, message_count
            FROM aicippy_com_conversations
            WHERE user_id = $1
            ORDER BY updated_at DESC
            LIMIT $2
            """,
            user_id,
            limit,
        )
        return [dict(row) for row in rows]

    async def get_tenant_memories(
        self,
        user_id: str,
    ) -> dict[str, Any]:
        """Read tenant memory entries directly from the tenant database.

        Args:
            user_id: User identifier.

        Returns:
            Dict of key -> value pairs.

        """
        pool = await self._ensure_pool()
        rows = await pool.fetch(
            """
            SELECT key, value
            FROM aicippy_com_tenant_memory
            WHERE user_id = $1
            """,
            user_id,
        )
        return {row["key"]: row["value"] for row in rows}

    async def close(self) -> None:
        """Close the connection pool."""
        if self._pool is not None:
            await self._pool.close()
            self._pool = None
            logger.info(
                "tenant_db_pool_closed",
                tenant_id=self._tenant_id,
            )

    async def __aenter__(self) -> TenantDBReader:
        """Enter the async context manager."""
        await self._ensure_pool()
        return self

    async def __aexit__(self, *args: object) -> None:
        """Exit the async context manager and close the pool."""
        await self.close()
