import { Response } from "express"; import { SendMessageDTO, CreateEventDTO, UpdateEventDTO, EventAction, GetMessagesOptions, RecurringDeleteMode, } from "@calchat/shared"; import { ChatService } from "../services"; import { CaldavService } from "../services/CaldavService"; import { createLogger } from "../logging"; import { AuthenticatedRequest } from "./AuthMiddleware"; const log = createLogger("ChatController"); export class ChatController { constructor( private chatService: ChatService, private caldavService: CaldavService, ) {} async sendMessage(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user!.userId; const data: SendMessageDTO = req.body; const response = await this.chatService.processMessage(userId, data); res.json(response); } catch (error) { log.error( { err: error, userId: req.user?.userId }, "Error processing message", ); res.status(500).json({ error: "Failed to process message" }); } } async confirmEvent(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user!.userId; const { conversationId, messageId } = req.params; // DEBUG: Log incoming request body to trace deleteMode issue log.debug({ body: req.body }, "confirmEvent request body"); const { proposalId, action, event, eventId, updates, deleteMode, occurrenceDate, } = req.body as { proposalId: string; action: EventAction; event?: CreateEventDTO; eventId?: string; updates?: UpdateEventDTO; deleteMode?: RecurringDeleteMode; occurrenceDate?: string; }; const response = await this.chatService.confirmEvent( userId, conversationId, messageId, proposalId, action, event, eventId, updates, deleteMode, occurrenceDate, ); // Sync confirmed event to CalDAV try { if (await this.caldavService.getConfig(userId)) { await this.caldavService.pushAll(userId); } } catch (error) { log.error({ err: error, userId }, "CalDAV push after confirm failed"); } res.json(response); } catch (error) { log.error( { err: error, conversationId: req.params.conversationId }, "Error confirming event", ); res.status(500).json({ error: "Failed to confirm event" }); } } async rejectEvent(req: AuthenticatedRequest, res: Response): Promise { try { const userId = req.user!.userId; const { conversationId, messageId } = req.params; const { proposalId } = req.body as { proposalId: string }; const response = await this.chatService.rejectEvent( userId, conversationId, messageId, proposalId, ); res.json(response); } catch (error) { log.error( { err: error, conversationId: req.params.conversationId }, "Error rejecting event", ); res.status(500).json({ error: "Failed to reject event" }); } } async getConversations( req: AuthenticatedRequest, res: Response, ): Promise { try { const userId = req.user!.userId; const conversations = await this.chatService.getConversations(userId); res.json(conversations); } catch (error) { log.error( { err: error, userId: req.user?.userId }, "Error getting conversations", ); res.status(500).json({ error: "Failed to get conversations" }); } } async getConversation( req: AuthenticatedRequest, res: Response, ): Promise { try { const userId = req.user!.userId; const { id } = req.params; const { before, limit } = req.query as { before?: string; limit?: string; }; const options: GetMessagesOptions = {}; if (before) options.before = before; if (limit) options.limit = parseInt(limit, 10); const messages = await this.chatService.getConversation( userId, id, options, ); res.json(messages); } catch (error) { if ((error as Error).message === "Conversation not found") { res.status(404).json({ error: "Conversation not found" }); } else { log.error( { err: error, conversationId: req.params.id }, "Error getting conversation", ); res.status(500).json({ error: "Failed to get conversation" }); } } } async updateProposalEvent( req: AuthenticatedRequest, res: Response, ): Promise { try { const { messageId } = req.params; const { proposalId, event } = req.body as { proposalId: string; event: CreateEventDTO; }; const message = await this.chatService.updateProposalEvent( messageId, proposalId, event, ); if (message) { res.json(message); } else { res.status(404).json({ error: "Message or proposal not found" }); } } catch (error) { log.error( { err: error, messageId: req.params.messageId }, "Error updating proposal event", ); res.status(500).json({ error: "Failed to update proposal event" }); } } }