# app/core/database.py
"""
Database configuration and session management.

This module provides classes and functions for:
- PostgreSQL database engine creation and configuration
- Session management with connection pooling
- Database dependency for FastAPI routes

Note: This project uses PostgreSQL only. SQLite is not supported.
"""

import logging

from sqlalchemy import create_engine, event
from sqlalchemy.orm import declarative_base, sessionmaker, with_loader_criteria
from sqlalchemy.pool import QueuePool

from .config import settings, validate_database_url

# Validate database URL on import
validate_database_url()

# Create PostgreSQL engine with connection pooling
engine = create_engine(
    settings.database_url,
    poolclass=QueuePool,
    pool_size=10,
    max_overflow=20,
    pool_pre_ping=True,
    echo=False,
)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
# Soft-delete automatic query filter
# ---------------------------------------------------------------------------
# Any model that inherits SoftDeleteMixin will automatically have
# `WHERE deleted_at IS NULL` appended to SELECT queries.
# Bypass with: db.execute(stmt, execution_options={"include_deleted": True})
# or db.query(Model).execution_options(include_deleted=True).all()
# ---------------------------------------------------------------------------

def register_soft_delete_filter(session_factory):
    """Register the soft-delete query filter on a session factory.

    Call this for any sessionmaker that should auto-exclude soft-deleted records.
    Used for both the production SessionLocal and test session factories.
    """

    @event.listens_for(session_factory, "do_orm_execute")
    def _soft_delete_filter(orm_execute_state):
        if (
            orm_execute_state.is_select
            and not orm_execute_state.execution_options.get("include_deleted", False)
        ):
            from models.database.base import SoftDeleteMixin

            orm_execute_state.statement = orm_execute_state.statement.options(
                with_loader_criteria(
                    SoftDeleteMixin,
                    lambda cls: cls.deleted_at.is_(None),
                    include_aliases=True,
                )
            )

    return _soft_delete_filter


# Register on the production session factory
register_soft_delete_filter(SessionLocal)


def get_db():
    """
    Database session dependency for FastAPI routes.

    Yields a database session and ensures proper cleanup.
    Handles exceptions and rolls back transactions on error.
    """
    db = SessionLocal()
    try:
        yield db
    except Exception as e:
        logger.error(f"Database session error: {e}")
        db.rollback()
        raise
    finally:
        db.close()
