"""Database configuration and session management."""

from collections.abc import Generator
from contextlib import contextmanager

from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import sessionmaker

from fenliu.config import settings
from fenliu.logging import get_logger

logger = get_logger(__name__)

# Create SQLAlchemy engine
logger.debug(f"database: creating engine with URL={settings.database_url}")
engine = create_engine(
    settings.database_url,
    connect_args={"check_same_thread": False} if settings.database_url.startswith("sqlite") else {},
    echo=settings.debug,
    pool_pre_ping=True,
)
logger.debug("database: engine created successfully")

# Create session factory
SessionLocal = sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine,
    expire_on_commit=False,
)
logger.debug("database: session factory created")

# Create declarative base class
Base = declarative_base()


@contextmanager
def get_db() -> Generator[Session, None, None]:
    """Context manager to get a database session.

    Usage::

        with get_db() as db:
            result = db.execute(select(Post))

    The session is always closed on exit, even if an exception is raised.
    """
    logger.debug("get_db: opening new database session")
    db = SessionLocal()
    try:
        yield db
    except Exception as e:
        logger.debug(f"get_db: exception occurred: {e}")
        raise
    finally:
        logger.debug("get_db: closing database session")
        db.close()


def create_tables() -> None:
    """Create all database tables directly via SQLAlchemy.

    .. warning::
        This function is intended for use in tests only.
        In production and development, schema changes are managed by Alembic.
        Run ``alembic upgrade head`` to apply migrations instead.
    """
    logger.debug("create_tables: creating all database tables")
    Base.metadata.create_all(bind=engine)
    logger.debug("create_tables: completed")
