import { Socket } from "socket.io";
import { attachSocketEventPermissions } from "../middleware/authorization";
import { opportunities } from "../../../managers/opportunities";

const LIVE_QUOTE_PREVIEW_PERMISSION = "sales.opportunity.quote.preview";

export const registerLiveQuotePreviewHandlers = (socket: Socket) => {
  attachSocketEventPermissions(socket, {
    "opp:live_quote_preview": [LIVE_QUOTE_PREVIEW_PERMISSION],
  });

  const registeredLivePreviewEvents = new Set<string>();

  socket.on(
    "opp:live_quote_preview",
    async (
      payload: { id?: string | number },
      ack?: (response: { ok: boolean; event?: string; error?: string }) => void
    ) => {
      const oppId = payload?.id;
      const normalizedId =
        typeof oppId === "string" || typeof oppId === "number"
          ? `${oppId}`
          : "";

      if (!normalizedId) {
        if (ack) return ack({ ok: false, error: "Missing opportunity id" });
        socket.emit("opp:live_quote_preview:error", {
          message: "Missing opportunity id",
        });
        return;
      }

      const dataEvent = `opp:live_quote_preview:${normalizedId}:data`;
      const previewEvent = `opp:live_quote_preview:${normalizedId}:preview`;
      const roomName = `opp:live_quote_preview:${normalizedId}`;

      if (!registeredLivePreviewEvents.has(dataEvent)) {
        registeredLivePreviewEvents.add(dataEvent);
        socket.join(roomName);

        socket.on(dataEvent, async (data: any) => {
          socket.to(roomName).emit(dataEvent, data);

          try {
            const opportunity = await opportunities.fetchRecord(normalizedId);
            const opts =
              data?.options && typeof data.options === "object"
                ? data.options
                : data;

            const previewBuffer = await opportunity.generateQuote({
              lineItemPricing: opts?.lineItemPricing,
              includeQuoteNarrative: opts?.includeQuoteNarrative,
              includeItemNarratives: opts?.includeItemNarratives,
              separateRecurringServices: opts?.separateRecurringServices,
              logoPath: opts?.logoPath,
              showPreview: true,
            });

            const previewBase64 = Buffer.from(previewBuffer).toString("base64");

            socket.to(roomName).emit(previewEvent, {
              id: normalizedId,
              mimeType: "application/pdf",
              contentBase64: previewBase64,
            });

            socket.to(roomName).emit(dataEvent, {
              id: normalizedId,
              mimeType: "application/pdf",
              contentBase64: previewBase64,
            });

            socket.emit(previewEvent, {
              id: normalizedId,
              mimeType: "application/pdf",
              contentBase64: previewBase64,
            });

            socket.emit(dataEvent, {
              id: normalizedId,
              mimeType: "application/pdf",
              contentBase64: previewBase64,
            });
          } catch (err: any) {
            socket.emit("opp:live_quote_preview:error", {
              message: err?.message ?? "Failed to generate live quote preview",
              id: normalizedId,
            });
          }
        });
      }

      if (ack) return ack({ ok: true, event: dataEvent });

      socket.emit("opp:live_quote_preview:ready", {
        id: normalizedId,
        event: dataEvent,
      });
    }
  );
};
