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<void> {
    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<void> {
    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<void> {
    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<void> {
    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<void> {
    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<void> {
    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" });
    }
  }
}
