"""Prioritization Engine โ€” generates actionable suggestions based on task state.""" from datetime import datetime, timedelta from zoneinfo import ZoneInfo from sqlalchemy.orm import Session from app.models import Task BERLIN_TZ = ZoneInfo("Europe/Berlin") def generate_suggestions(db: Session) -> list[dict]: """Analyze open tasks and generate prioritization suggestions. Returns a list of suggestion dicts with: id, content, type, severity. """ now = datetime.now(BERLIN_TZ) today = now.date() suggestions = [] suggestion_id = 1 open_tasks = db.query(Task).filter(Task.status == "open").all() if not open_tasks: return [] # --- 1. Overdue tasks --- overdue_tasks = [ t for t in open_tasks if t.due_date and t.due_date.date() < today ] for t in overdue_tasks[:3]: # Limit to top 3 days_overdue = (today - t.due_date.date()).days suggestions.append({ "id": suggestion_id, "content": f"โš ๏ธ \"{t.title}\" is {days_overdue} day{'s' if days_overdue != 1 else ''} overdue. Reschedule or complete it.", "type": "overdue", "severity": "high", "task_id": t.id, }) suggestion_id += 1 # --- 2. Due tomorrow --- tomorrow = today + timedelta(days=1) due_tomorrow = [ t for t in open_tasks if t.due_date and t.due_date.date() == tomorrow ] for t in due_tomorrow: suggestions.append({ "id": suggestion_id, "content": f"๐Ÿ“… \"{t.title}\" is due tomorrow.", "type": "upcoming", "severity": "medium", "task_id": t.id, }) suggestion_id += 1 # --- 3. Due this week --- week_end = today + timedelta(days=7) due_this_week = [ t for t in open_tasks if t.due_date and today < t.due_date.date() <= week_end and t.due_date.date() != tomorrow # Already covered above ] if len(due_this_week) > 3: suggestions.append({ "id": suggestion_id, "content": f"๐Ÿ“‹ You have {len(due_this_week)} tasks due this week. Plan your time.", "type": "workload", "severity": "medium", }) suggestion_id += 1 # --- 4. High-priority tasks without due dates --- high_no_date = [ t for t in open_tasks if t.priority and t.priority <= 2 and not t.due_date ] for t in high_no_date[:2]: # Limit to top 2 suggestions.append({ "id": suggestion_id, "content": f"๐ŸŽฏ \"{t.title}\" is high priority but has no deadline. Set a due date.", "type": "missing_date", "severity": "medium", "task_id": t.id, }) suggestion_id += 1 # --- 5. Tasks idle for 7+ days --- idle_threshold = now - timedelta(days=7) idle_tasks = [ t for t in open_tasks if t.created_at and t.created_at < idle_threshold and (not t.due_date) # Only flag idle tasks without deadlines and t.priority and t.priority >= 3 # Low/medium priority ] if len(idle_tasks) > 5: suggestions.append({ "id": suggestion_id, "content": f"๐Ÿงน {len(idle_tasks)} low-priority tasks have been sitting for over a week. Review and clean up.", "type": "stale", "severity": "low", }) suggestion_id += 1 elif idle_tasks: oldest = max(idle_tasks, key=lambda t: (now - t.created_at).days if t.created_at else 0) if oldest.created_at: days_idle = (now - oldest.created_at).days suggestions.append({ "id": suggestion_id, "content": f"๐Ÿงน \"{oldest.title}\" has been open for {days_idle} days. Still relevant?", "type": "stale", "severity": "low", "task_id": oldest.id, }) suggestion_id += 1 # --- 6. Too many high-priority tasks --- high_priority_count = len([t for t in open_tasks if t.priority and t.priority <= 2]) if high_priority_count > 5: suggestions.append({ "id": suggestion_id, "content": f"๐Ÿ”ฅ You have {high_priority_count} high-priority tasks. If everything is urgent, nothing is. Consider demoting some.", "type": "overload", "severity": "medium", }) suggestion_id += 1 # --- 7. No tasks due soon (might need planning) --- tasks_with_dates = [t for t in open_tasks if t.due_date] if len(open_tasks) > 10 and len(tasks_with_dates) < 3: suggestions.append({ "id": suggestion_id, "content": "๐Ÿ“† Most of your tasks have no due dates. Consider scheduling your top priorities.", "type": "planning", "severity": "low", }) suggestion_id += 1 return suggestions