from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession  # Import necessary async SQLAlchemy components
from sqlalchemy.orm import sessionmaker  # Import sessionmaker for handling database sessions
from src.models.base import Base  # Import the base model which contains metadata for all tables
import os  # Import OS module to read environment variables
from typing import AsyncGenerator  # Import AsyncGenerator to define the return type of the async database session function
from dotenv import load_dotenv  # Import load_dotenv to load environment variables from a .env file
load_dotenv()  # Load environment variables from a .env file
# Read the database URL from environment variables (useful for different environments like dev, prod, test)
DATABASE_URL = os.getenv("DATABASE_URL")  
print(DATABASE_URL)

# Create an asynchronous database engine
engine = create_async_engine(
    DATABASE_URL,      # The database connection string
    pool_size=10,      # Maintain a pool of up to 10 open connections
    max_overflow=20    # Allow up to 20 additional temporary connections when needed
)

# Create an asynchronous session factory
async_session = sessionmaker(
    engine,                  # Bind sessions to the async database engine
    class_=AsyncSession,     # Use AsyncSession for async operations
    expire_on_commit=False   # Prevent automatic expiration of objects (useful to access data after committing)
)

async def init_db():
    """
    Initialize database tables by creating them if they don’t exist.
    This function runs at application startup.
    """
    async with engine.begin() as conn:  # Open an async connection to the database
        await conn.run_sync(Base.metadata.create_all)  # Create tables based on the models defined in Base.metadata

async def get_db() -> AsyncGenerator[AsyncSession, None]:
    """
    Dependency function to provide an async database session.
    Used in FastAPI route handlers to manage transactions efficiently.
    """
    async with async_session() as session:  # Create a new session for each request
        yield session  # Yield the session to be used in the route
