import type { Project, Tag, Composition, InteractionLink } from "@/shared/types"
import type { FrontendPayload } from "@/types"
import type { FastifyInstance } from "fastify"

export const createSystemEventHandlers = (fastify: FastifyInstance) => {
  const { wss } = fastify

  const sendToChannel = (payload: FrontendPayload<unknown>, key: string) => {
    // TODO rework this to handle spaces instead of project and in the future document rooms -> y.js?
    // Is this even used? SocketManager also has wss.emit
    fastify.log.debug(
      `[Socket] sendToChannel ${key} to room ${payload.project}${payload.workSessionId ? ' and workSession ' + payload.workSessionId : ''}`,
    )
    if (payload.project) {
      wss.in(payload.project).emit(key, payload)
    } else {
      wss.emit(key, payload)
    }
    if (payload.workSessionId) {
      wss.in(payload.workSessionId).emit(key, payload)
    }
  }

  return {
    broadcastDataUpdated: (payload: FrontendPayload<unknown>): void => {
      fastify.log.info(`[Socket] Push onData: ${payload.appSessionId}`)
      sendToChannel(payload, "data")
    },
    broadcastDataCreated: (payload: FrontendPayload<unknown>): void => {
      fastify.log.info(`[Socket] Push onCreate: ${payload.appSessionId}`)
      sendToChannel(payload, "dataCreated")
    },
    broadcastDataDeleted: (payload: FrontendPayload<unknown>): void => {
      fastify.log.info(`[Socket] Push onDelete: ${payload.appSessionId}`)
      sendToChannel(payload, "dataDeleted")
    },
    broadcastCompositionCreated: (
      payload: FrontendPayload<Composition>,
    ): void => {
      fastify.log.info(
        `[Socket] Push CompositionCreated: ${payload.appSessionId}`,
      )
      sendToChannel(payload, "compositionCreated")
    },

    broadcastCompositionDeleted: (
      payload: FrontendPayload<Composition>,
    ): void => {
      fastify.log.info(
        `[Socket] Push CompositionDeleted: ${payload.appSessionId}`,
      )
      sendToChannel(payload, "compositionDeleted")
    },
    broadcastInteractionLinkCreated: (
      payload: FrontendPayload<InteractionLink>,
    ): void => {
      fastify.log.info(
        `[Socket] Push InteractionLinkCreated: ${payload.appSessionId}`,
      )
      sendToChannel(payload, "interactionLinkCreated")
    },

    broadcastInteractionLinkDeleted: (
      payload: FrontendPayload<InteractionLink>,
    ): void => {
      fastify.log.info(
        `[Socket] Push InteractionLinkDeleted: ${payload.appSessionId}`,
      )
      sendToChannel(payload, "interactionLinkDeleted")
    },
    broadcastTagCreated: (payload: FrontendPayload<Tag>): void => {
      fastify.log.info(`[Socket] Push tagCreated: ${payload.appSessionId}`)
      sendToChannel(payload, "tagCreated")
    },

    broadcastTagDeleted: (payload: FrontendPayload<Tag>): void => {
      fastify.log.info(`[Socket] Push tagDeleted: ${payload.appSessionId}`)
      sendToChannel(payload, "tagDeleted")
    },

    broadcastUserCreated: (payload: FrontendPayload<Tag>): void => {
      fastify.log.info(`[Socket] Push userCreated: ${payload.appSessionId}`)
      sendToChannel(payload, "userCreated")
    },

    broadcastUserDeleted: (payload: FrontendPayload<Tag>): void => {
      fastify.log.info(`[Socket] Push userDeleted: ${payload.appSessionId}`)
      sendToChannel(payload, "userDeleted")
    },

    broadcastProjectCreated: (payload: FrontendPayload<Project>): void => {
      fastify.log.info(`[Socket] Push projectCreated: ${payload.appSessionId}`)
      sendToChannel(payload, "projectCreated")
    },

    broadcastProjectUpdated: (payload: FrontendPayload<Project>): void => {
      fastify.log.info(`[Socket] Push projectUpdated: ${payload.appSessionId}`)
      sendToChannel(payload, "projectUpdated")
    },

    broadcastProjectConfigUpdated: (
      payload: FrontendPayload<Project>,
    ): void => {
      fastify.log.info(`[Socket] Push projectDeleted: ${payload.appSessionId}`)
      sendToChannel(payload, "projectDeleted")
    },

    broadcastNewVersionAvailable: (): void => {
      wss.emit("newVersionAvailable")
      fastify.log.info("[Socket] push new version available #all")
    },
  }
}
