""" Mail Database - Inbox Task Operations. """ import uuid from typing import Optional, List, Dict from datetime import datetime, timedelta from .mail_db_pool import get_pool async def create_task( user_id: str, tenant_id: str, title: str, description: Optional[str] = None, priority: str = "medium", deadline: Optional[datetime] = None, email_id: Optional[str] = None, account_id: Optional[str] = None, source_email_subject: Optional[str] = None, source_sender: Optional[str] = None, source_sender_type: Optional[str] = None, ai_extracted: bool = False, confidence_score: Optional[float] = None, ) -> Optional[str]: """Create a new inbox task.""" pool = await get_pool() if pool is None: return None task_id = str(uuid.uuid4()) try: async with pool.acquire() as conn: await conn.execute( """ INSERT INTO inbox_tasks (id, user_id, tenant_id, title, description, priority, deadline, email_id, account_id, source_email_subject, source_sender, source_sender_type, ai_extracted, confidence_score) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) """, task_id, user_id, tenant_id, title, description, priority, deadline, email_id, account_id, source_email_subject, source_sender, source_sender_type, ai_extracted, confidence_score ) return task_id except Exception as e: print(f"Failed to create task: {e}") return None async def get_tasks( user_id: str, status: Optional[str] = None, priority: Optional[str] = None, include_completed: bool = False, limit: int = 50, offset: int = 0, ) -> List[Dict]: """Get tasks for a user.""" pool = await get_pool() if pool is None: return [] try: async with pool.acquire() as conn: conditions = ["user_id = $1"] params = [user_id] param_idx = 2 if not include_completed: conditions.append("status != 'completed'") if status: conditions.append(f"status = ${param_idx}") params.append(status) param_idx += 1 if priority: conditions.append(f"priority = ${param_idx}") params.append(priority) param_idx += 1 where_clause = " AND ".join(conditions) params.extend([limit, offset]) query = f""" SELECT * FROM inbox_tasks WHERE {where_clause} ORDER BY CASE priority WHEN 'urgent' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 WHEN 'low' THEN 4 END, deadline ASC NULLS LAST, created_at DESC LIMIT ${param_idx} OFFSET ${param_idx + 1} """ rows = await conn.fetch(query, *params) return [dict(r) for r in rows] except Exception as e: print(f"Failed to get tasks: {e}") return [] async def get_task(task_id: str, user_id: str) -> Optional[Dict]: """Get a single task.""" pool = await get_pool() if pool is None: return None try: async with pool.acquire() as conn: row = await conn.fetchrow( "SELECT * FROM inbox_tasks WHERE id = $1 AND user_id = $2", task_id, user_id ) return dict(row) if row else None except Exception as e: print(f"Failed to get task: {e}") return None async def update_task( task_id: str, user_id: str, title: Optional[str] = None, description: Optional[str] = None, priority: Optional[str] = None, status: Optional[str] = None, deadline: Optional[datetime] = None, ) -> bool: """Update a task.""" pool = await get_pool() if pool is None: return False try: async with pool.acquire() as conn: updates = ["updated_at = NOW()"] params = [task_id, user_id] param_idx = 3 if title is not None: updates.append(f"title = ${param_idx}") params.append(title) param_idx += 1 if description is not None: updates.append(f"description = ${param_idx}") params.append(description) param_idx += 1 if priority is not None: updates.append(f"priority = ${param_idx}") params.append(priority) param_idx += 1 if status is not None: updates.append(f"status = ${param_idx}") params.append(status) param_idx += 1 if status == "completed": updates.append("completed_at = NOW()") if deadline is not None: updates.append(f"deadline = ${param_idx}") params.append(deadline) param_idx += 1 set_clause = ", ".join(updates) await conn.execute( f"UPDATE inbox_tasks SET {set_clause} WHERE id = $1 AND user_id = $2", *params ) return True except Exception as e: print(f"Failed to update task: {e}") return False async def get_task_dashboard_stats(user_id: str) -> Dict: """Get dashboard statistics for tasks.""" pool = await get_pool() if pool is None: return {} try: async with pool.acquire() as conn: now = datetime.now() today_end = now.replace(hour=23, minute=59, second=59) week_end = now + timedelta(days=7) stats = await conn.fetchrow( """ SELECT COUNT(*) as total_tasks, COUNT(*) FILTER (WHERE status = 'pending') as pending_tasks, COUNT(*) FILTER (WHERE status = 'in_progress') as in_progress_tasks, COUNT(*) FILTER (WHERE status = 'completed') as completed_tasks, COUNT(*) FILTER (WHERE status != 'completed' AND deadline < $2) as overdue_tasks, COUNT(*) FILTER (WHERE status != 'completed' AND deadline <= $3) as due_today, COUNT(*) FILTER (WHERE status != 'completed' AND deadline <= $4) as due_this_week FROM inbox_tasks WHERE user_id = $1 """, user_id, now, today_end, week_end ) by_priority = await conn.fetch( """ SELECT priority, COUNT(*) as count FROM inbox_tasks WHERE user_id = $1 AND status != 'completed' GROUP BY priority """, user_id ) by_sender = await conn.fetch( """ SELECT source_sender_type, COUNT(*) as count FROM inbox_tasks WHERE user_id = $1 AND status != 'completed' AND source_sender_type IS NOT NULL GROUP BY source_sender_type """, user_id ) return { "total_tasks": stats['total_tasks'] or 0, "pending_tasks": stats['pending_tasks'] or 0, "in_progress_tasks": stats['in_progress_tasks'] or 0, "completed_tasks": stats['completed_tasks'] or 0, "overdue_tasks": stats['overdue_tasks'] or 0, "due_today": stats['due_today'] or 0, "due_this_week": stats['due_this_week'] or 0, "by_priority": {r['priority']: r['count'] for r in by_priority}, "by_sender_type": {r['source_sender_type']: r['count'] for r in by_sender}, } except Exception as e: print(f"Failed to get task stats: {e}") return {}