import { Response } from 'express'; import { validate, taskCreationSchema, taskUpdateSchema } from '@/utils/validation'; import prisma from '@/utils/database'; import logger from '@/utils/logger'; import { AuthenticatedRequest, CreateTaskData, UpdateTaskData, ApiResponse } from '@/types'; import { suggestOptimalTime } from '@/services/aiService'; import { sendTaskReminder } from '@/services/whatsappService'; export const createTask = async (req: AuthenticatedRequest, res: Response) => { try { const taskData: CreateTaskData = validate(taskCreationSchema, req.body); const userId = req.user!.id; let aiSuggestedTime = null; if (taskData.dueDate && !taskData.scheduledAt) { aiSuggestedTime = await suggestOptimalTime(taskData.dueDate, taskData.priority || 'MEDIUM'); } const task = await prisma.task.create({ data: { title: taskData.title, description: taskData.description, priority: taskData.priority || 'MEDIUM', dueDate: taskData.dueDate, scheduledAt: taskData.scheduledAt, aiSuggestedTime, ownerId: userId, }, include: { owner: { select: { id: true, email: true, fullName: true, } } } }); logger.info(`Task created: ${task.title} by user ${userId}`); return res.status(201).json({ success: true, message: 'Task created successfully', data: task } as ApiResponse); } catch (error) { logger.error('Task creation error:', error); return res.status(400).json({ success: false, message: error instanceof Error ? error.message : 'Task creation failed' } as ApiResponse); } }; export const getTasks = async (req: AuthenticatedRequest, res: Response) => { try { const userId = req.user!.id; const { status, priority, page = '1', limit = '20' } = req.query; const pageNum = parseInt(page as string); const limitNum = parseInt(limit as string); const skip = (pageNum - 1) * limitNum; const where: any = { ownerId: userId }; if (status) where.status = status; if (priority) where.priority = priority; const [tasks, total] = await Promise.all([ prisma.task.findMany({ where, orderBy: { createdAt: 'desc' }, skip, take: limitNum, include: { owner: { select: { id: true, email: true, fullName: true, } } } }), prisma.task.count({ where }) ]); return res.status(200).json({ success: true, message: 'Tasks retrieved successfully', data: { tasks, pagination: { page: pageNum, limit: limitNum, total, pages: Math.ceil(total / limitNum) } } } as ApiResponse); } catch (error) { logger.error('Get tasks error:', error); return res.status(500).json({ success: false, message: 'Failed to retrieve tasks' } as ApiResponse); } }; export const getTask = async (req: AuthenticatedRequest, res: Response) => { try { const taskId = parseInt(req.params.id); const userId = req.user!.id; const task = await prisma.task.findFirst({ where: { id: taskId, ownerId: userId }, include: { owner: { select: { id: true, email: true, fullName: true, } } } }); if (!task) { return res.status(404).json({ success: false, message: 'Task not found' } as ApiResponse); } return res.status(200).json({ success: true, message: 'Task retrieved successfully', data: task } as ApiResponse); } catch (error) { logger.error('Get task error:', error); return res.status(500).json({ success: false, message: 'Failed to retrieve task' } as ApiResponse); } }; export const updateTask = async (req: AuthenticatedRequest, res: Response) => { try { const taskId = parseInt(req.params.id); const userId = req.user!.id; const updateData: UpdateTaskData = validate(taskUpdateSchema, req.body); const existingTask = await prisma.task.findFirst({ where: { id: taskId, ownerId: userId } }); if (!existingTask) { return res.status(404).json({ success: false, message: 'Task not found' } as ApiResponse); } const updatePayload: any = { ...updateData }; if (updateData.status === 'COMPLETED' && existingTask.status !== 'COMPLETED') { updatePayload.completedAt = new Date(); } const task = await prisma.task.update({ where: { id: taskId }, data: updatePayload, include: { owner: { select: { id: true, email: true, fullName: true, } } } }); logger.info(`Task updated: ${task.title} by user ${userId}`); return res.status(200).json({ success: true, message: 'Task updated successfully', data: task } as ApiResponse); } catch (error) { logger.error('Task update error:', error); return res.status(400).json({ success: false, message: error instanceof Error ? error.message : 'Task update failed' } as ApiResponse); } }; export const deleteTask = async (req: AuthenticatedRequest, res: Response) => { try { const taskId = parseInt(req.params.id); const userId = req.user!.id; const task = await prisma.task.findFirst({ where: { id: taskId, ownerId: userId } }); if (!task) { return res.status(404).json({ success: false, message: 'Task not found' } as ApiResponse); } await prisma.task.delete({ where: { id: taskId } }); logger.info(`Task deleted: ${task.title} by user ${userId}`); return res.status(200).json({ success: true, message: 'Task deleted successfully' } as ApiResponse); } catch (error) { logger.error('Task deletion error:', error); return res.status(500).json({ success: false, message: 'Failed to delete task' } as ApiResponse); } }; export const sendReminder = async (req: AuthenticatedRequest, res: Response) => { try { const taskId = parseInt(req.params.id); const userId = req.user!.id; const task = await prisma.task.findFirst({ where: { id: taskId, ownerId: userId }, include: { owner: true } }); if (!task) { return res.status(404).json({ success: false, message: 'Task not found' } as ApiResponse); } if (!task.owner.whatsappNumber) { return res.status(400).json({ success: false, message: 'WhatsApp number not configured' } as ApiResponse); } const success = await sendTaskReminder(task.owner.whatsappNumber, task); if (success) { await prisma.task.update({ where: { id: taskId }, data: { whatsappReminderSent: true } }); return res.status(200).json({ success: true, message: 'Reminder sent successfully' } as ApiResponse); } else { return res.status(500).json({ success: false, message: 'Failed to send reminder' } as ApiResponse); } } catch (error) { logger.error('Send reminder error:', error); return res.status(500).json({ success: false, message: 'Failed to send reminder' } as ApiResponse); } };