"""DB-backed tests for R6 S2 quota transaction ownership: quota accounting writes in its OWN
session, so a spend is DURABLE even when the calling job rolls back (the units were really consumed
at YouTube), and it NEVER commits the caller's session (the old behaviour flushed a job's partial
state mid-run behind its own rollback). Uses the DB lane (`db` fixture) — skipped without Postgres.
"""
from sqlalchemy import func, select

from app import quota
from app.models import QuotaEvent, User


def test_record_usage_survives_caller_rollback_and_leaves_caller_uncommitted(db):
    # The caller has uncommitted work of its own; then a YouTube call spends quota; then the caller
    # rolls back (a failed job).
    db.add(User(email="pending@example.com"))  # caller's own, never committed
    quota.record_usage(10)                      # dedicated session — commits independently
    db.rollback()                               # the job fails and rolls back

    # Quota spend PERSISTED (real units were consumed) — the guard stays accurate ...
    assert quota.units_used_today(db) == 10
    assert db.scalar(select(func.count()).select_from(QuotaEvent)) == 1
    # ... but the caller's own partial work did NOT leak (quota never committed the caller's session).
    assert db.scalar(select(func.count()).select_from(User).where(User.email == "pending@example.com")) == 0


def test_record_usage_accumulates(db):
    quota.record_usage(10)
    quota.record_usage(5)
    assert quota.units_used_today(db) == 15  # atomic upsert: +10 then +5


def test_reads_see_separate_session_spend_mid_transaction(db):
    # Mimics measured()'s before/after diff: a read, a spend (in quota's SEPARATE session), a read.
    # The second read must reflect the spend even though the caller's own transaction is still open —
    # units_used_today is a scalar SELECT (READ COMMITTED sees other sessions' commits), NOT a cached
    # ORM row that db.get would return stale.
    before = quota.units_used_today(db)
    quota.record_usage(7)
    after = quota.units_used_today(db)
    assert after - before == 7


def test_log_action_survives_caller_rollback(db):
    user = User(email="searcher@example.com")
    db.add(user)
    db.commit()  # a committed user to attribute the (free) action to
    db.add(User(email="pending@example.com"))  # uncommitted caller work
    quota.log_action(user.id, quota.QuotaAction.VIDEOS_SEARCH)
    db.rollback()

    # The zero-cost action event survived (per-user daily caps must still count it) ...
    events = db.execute(select(QuotaEvent)).scalars().all()
    assert len(events) == 1
    assert events[0].user_id == user.id
    assert events[0].units == 0
    # ... and the caller's uncommitted user is gone.
    assert db.scalar(select(func.count()).select_from(User)) == 1
