""" ReminderScheduler Schedules and manages user reminders. """ from datetime import UTC, datetime, timedelta from typing import TYPE_CHECKING from sqlalchemy import select, and_ from app.models.reminder import Reminder if TYPE_CHECKING: from sqlalchemy.ext.asyncio import AsyncSession class ReminderScheduler: """Schedule and manage user reminders.""" async def create_reminder( self, db: "AsyncSession", user_id: str, content: str, trigger_at: datetime, trigger_type: str = "time", context_memory_id: str | None = None, ) -> Reminder: """Create a new reminder.""" reminder = Reminder( user_id=user_id, content=content, trigger_type=trigger_type, trigger_at=trigger_at, context_memory_id=context_memory_id, status="pending", ) db.add(reminder) await db.commit() await db.refresh(reminder) return reminder async def get_due_reminders(self, db: "AsyncSession", user_id: str) -> list[Reminder]: """Get reminders that are due (status=pending, trigger_at <= now, not snoozed).""" now = datetime.now(UTC) result = await db.execute( select(Reminder) .where( Reminder.user_id == user_id, Reminder.status == "pending", Reminder.trigger_at <= now, ((Reminder.snoozed_until.is_(None)) | (Reminder.snoozed_until <= now)), ) .order_by(Reminder.trigger_at.asc()) ) return list(result.scalars().all()) async def snooze( self, db: "AsyncSession", reminder_id: int, minutes: int, ) -> Reminder | None: """Snooze reminder for N minutes.""" result = await db.execute(select(Reminder).where(Reminder.id == reminder_id)) reminder = result.scalar_one_or_none() if not reminder: return None reminder.status = "snoozed" reminder.snoozed_until = datetime.now(UTC) + timedelta(minutes=minutes) await db.commit() await db.refresh(reminder) return reminder async def dismiss(self, db: "AsyncSession", reminder_id: int) -> bool: """Mark reminder as dismissed.""" result = await db.execute(select(Reminder).where(Reminder.id == reminder_id)) reminder = result.scalar_one_or_none() if not reminder: return False reminder.status = "dismissed" await db.commit() return True async def mark_sent(self, db: "AsyncSession", reminder_id: int) -> bool: """Mark reminder as sent.""" result = await db.execute(select(Reminder).where(Reminder.id == reminder_id)) reminder = result.scalar_one_or_none() if not reminder: return False reminder.status = "sent" await db.commit() return True async def get_pending_reminders( self, db: "AsyncSession", user_id: str, ) -> list[Reminder]: """Get all pending reminders for a user.""" result = await db.execute( select(Reminder) .where( Reminder.user_id == user_id, Reminder.status.in_(["pending", "snoozed"]), ) .order_by(Reminder.trigger_at.asc()) ) return list(result.scalars().all())