from contextlib import asynccontextmanager
from typing import AsyncIterator, Optional

from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorClientSession, AsyncIOMotorDatabase

from app.core.env import env_required, env_str
from app.core.logger import logger

_client: Optional[AsyncIOMotorClient] = None
_database: Optional[AsyncIOMotorDatabase] = None


async def connect_db() -> None:
    global _client, _database
    _client = AsyncIOMotorClient(env_required("MONGO_URI"))
    _database = _client[env_str("DATABASE_NAME", "repo_docs")]

    # Verify connectivity early so startup fails fast on bad DB config.
    await _database.command("ping")
    logger.info("MongoDB connection verified")


async def close_db() -> None:
    global _client, _database
    if _client:
        _client.close()
    _client = None
    _database = None


def get_db() -> AsyncIOMotorDatabase:
    if _database is None:
        raise RuntimeError("Database not initialized. Call connect_db() first.")
    return _database


def get_client() -> AsyncIOMotorClient:
    if _client is None:
        raise RuntimeError("MongoDB client is not initialized. Call connect_db() first.")
    return _client


@asynccontextmanager
async def mongo_session() -> AsyncIterator[AsyncIOMotorClientSession]:
    session = await get_client().start_session()
    try:
        yield session
    finally:
        session.end_session()


async def is_db_ready() -> bool:
    try:
        await get_db().command("ping")
        return True
    except Exception:
        return False