# retoor <retoor@molodetz.nl>

from devplacepy.cache import TTLCache
from .core import db, get_table
from .relations import get_blocked_uids


PAGE_SIZE = 25


_user_post_count_cache = TTLCache(ttl=15, max_size=2000)


def paginate(
    table,
    *clauses,
    before=None,
    order=None,
    cursor_field="created_at",
    viewer_uid=None,
    limit=PAGE_SIZE,
    **filters,
):
    order = order or ["-" + cursor_field]
    clauses = list(clauses)
    if table.has_column("deleted_at") and "deleted_at" not in filters:
        clauses.append(table.table.columns.deleted_at.is_(None))
    if viewer_uid and table.has_column("user_uid"):
        blocked = get_blocked_uids(viewer_uid)
        if blocked:
            clauses.append(table.table.columns.user_uid.notin_(blocked))
    if before:
        clauses.append(table.table.columns[cursor_field] < before)
    rows = list(table.find(*clauses, **filters, order_by=order, _limit=limit + 1))
    has_more = len(rows) > limit
    rows = rows[:limit]
    next_cursor = rows[-1][cursor_field] if has_more and rows else None
    return rows, next_cursor


def interleave_by_author(rows, uid_key="user_uid"):
    remaining = list(rows)
    spread = []
    last_owner = object()
    while remaining:
        pick = next(
            (
                index
                for index, row in enumerate(remaining)
                if row.get(uid_key) != last_owner
            ),
            0,
        )
        row = remaining.pop(pick)
        spread.append(row)
        last_owner = row.get(uid_key)
    return spread


def paginate_diverse(
    table,
    *clauses,
    before=None,
    order=None,
    cursor_field="created_at",
    uid_key="user_uid",
    viewer_uid=None,
    limit=PAGE_SIZE,
    **filters,
):
    rows, next_cursor = paginate(
        table,
        *clauses,
        before=before,
        order=order,
        cursor_field=cursor_field,
        viewer_uid=viewer_uid,
        limit=limit,
        **filters,
    )
    return interleave_by_author(rows, uid_key=uid_key), next_cursor


def clear_user_post_count(user_uid: str) -> None:
    _user_post_count_cache.pop(user_uid)


def get_user_post_count(user_uid: str) -> int:
    cached = _user_post_count_cache.get(user_uid)
    if cached is not None:
        return cached
    if "posts" not in db.tables:
        return 0
    count = get_table("posts").count(user_uid=user_uid, deleted_at=None)
    _user_post_count_cache.set(user_uid, count)
    return count


def build_pagination(page, total, per_page=25):
    total_pages = max(1, __import__("math").ceil(total / per_page))
    page = max(1, min(page, total_pages))
    return {
        "page": page,
        "per_page": per_page,
        "total": total,
        "total_pages": total_pages,
        "has_prev": page > 1,
        "has_next": page < total_pages,
        "prev_page": page - 1,
        "next_page": page + 1,
    }
