"""Shared timer-elapsed computation used by sessions and dashboard routers.""" from datetime import datetime from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from app.models.session import TimerEvent async def compute_block_elapsed( db: AsyncSession, session_id: int, block_id: int ) -> tuple[int, bool]: """Return (elapsed_seconds, is_paused) for a block. 'reset' events are treated as zero-elapsed restart markers: any elapsed time accumulated before a reset is discarded. """ tick_result = await db.execute( select(TimerEvent) .where( TimerEvent.session_id == session_id, TimerEvent.block_id == block_id, TimerEvent.event_type.in_(["start", "resume", "pause", "reset"]), ) .order_by(TimerEvent.occurred_at) ) tick_events = tick_result.scalars().all() elapsed = 0.0 last_start = None for e in tick_events: if e.event_type == "reset": elapsed = 0.0 last_start = e.occurred_at elif e.event_type in ("start", "resume"): last_start = e.occurred_at elif e.event_type == "pause" and last_start: elapsed += (e.occurred_at - last_start).total_seconds() last_start = None if last_start: elapsed += (datetime.utcnow() - last_start).total_seconds() is_paused = bool(tick_events) and tick_events[-1].event_type == "pause" return int(elapsed), is_paused async def compute_break_elapsed( db: AsyncSession, session_id: int, block_id: int ) -> tuple[int, bool]: """Return (break_elapsed_seconds, is_break_paused) for a block's break timer.""" tick_result = await db.execute( select(TimerEvent) .where( TimerEvent.session_id == session_id, TimerEvent.block_id == block_id, TimerEvent.event_type.in_(["break_start", "break_resume", "break_pause", "break_reset"]), ) .order_by(TimerEvent.occurred_at) ) tick_events = tick_result.scalars().all() elapsed = 0.0 last_start = None for e in tick_events: if e.event_type == "break_reset": elapsed = 0.0 last_start = e.occurred_at elif e.event_type in ("break_start", "break_resume"): last_start = e.occurred_at elif e.event_type == "break_pause" and last_start: elapsed += (e.occurred_at - last_start).total_seconds() last_start = None if last_start: elapsed += (datetime.utcnow() - last_start).total_seconds() is_paused = bool(tick_events) and tick_events[-1].event_type == "break_pause" return int(elapsed), is_paused