"""Helpers for the durable, server-backed per-user notification inbox (phase 1).

The inbox COEXISTS with the client-side transient "bell" (localStorage toasts): these rows
survive reloads/devices and are produced server-side. First producer is the maintenance
job. Unread rows never auto-expire; read rows are trimmed past a soft per-user cap so the
table can't grow without bound for a heavy user.
"""
from sqlalchemy import select
from sqlalchemy.orm import Session

from app.models import Notification

# Keep at most this many READ notifications per user; older read ones are pruned. Unread
# rows are never pruned (the user hasn't seen them yet).
READ_SOFT_CAP = 200


def create_notification(
    db: Session,
    user_id: int,
    type: str,
    title: str,
    body: str | None = None,
    data: dict | None = None,
    *,
    commit: bool = True,
) -> Notification:
    """Insert one notification for a user. Callers that batch many inserts in a single
    transaction can pass commit=False and commit once themselves."""
    notif = Notification(
        user_id=user_id, type=type, title=title, body=body, data=data
    )
    db.add(notif)
    if commit:
        db.commit()
        db.refresh(notif)
    return notif


def trim_read(db: Session, user_id: int, cap: int = READ_SOFT_CAP) -> int:
    """Delete a user's oldest READ notifications beyond `cap`. Returns the number removed.
    Idempotent and cheap; safe to call after marking things read."""
    ids = (
        db.execute(
            select(Notification.id)
            .where(Notification.user_id == user_id, Notification.read.is_(True))
            .order_by(Notification.created_at.desc())
            .offset(cap)
        )
        .scalars()
        .all()
    )
    if not ids:
        return 0
    for nid in ids:
        db.delete(db.get(Notification, nid))
    db.commit()
    return len(ids)
