from fastapi.encoders import jsonable_encoder
from sqlalchemy.sql import Select
from sqlalchemy.orm import Session
from sqlalchemy import asc, desc, select, func


def fetch_all(db: Session, stmt: Select):
    """
    Execute select statement and return JSON-serializable list
    """
    result = db.execute(stmt)
    return jsonable_encoder(result.mappings().all())


def fetch_one(db: Session, stmt: Select):
    """
    Return single row or None
    """
    result = db.execute(stmt).scalars().first()
    return jsonable_encoder(result) if result else None


def paginate(
    db: Session,
    stmt: Select,
    page: int = 1,
    per_page: int = 10,
    sort_by: str = "updated_at",
    sort_order: str = "desc",
):
    stmt_count = stmt.order_by(None)
    total = db.execute(select(func.count()).select_from(stmt_count.subquery())).scalar()
    stmt_limit = stmt.limit(per_page).offset((page - 1) * per_page)
    if sort_by in stmt.selected_columns:
        order = desc if sort_order == "desc" else asc
        sort_by = stmt.selected_columns[sort_by]
        stmt_limit = stmt_limit.order_by(order(sort_by))
    items = fetch_all(db, stmt_limit)
    return {
        "data": jsonable_encoder(items),
        "total": total,
        "page": page,
        "per_page": per_page,
        "last_page": (total + per_page - 1) // per_page,
    }
