import * as errors from '../../gen/errors'
import { setSpanAttributes, SPAN_ATTRS } from '../../tracing'
import * as msgPayload from '../message-payload'
import * as types from '../types'
import * as fid from './fid'
import * as model from './model'

export const createMessage: types.AuthenticatedOperations['createMessage'] = async (props, foreignReq) => {
  const fidHandler = fid.handlers.createMessage(props, foreignReq)
  const req = await fidHandler.mapRequest()

  const { conversationId, payload, metadata } = req.body
  const { userId } = req.auth

  setSpanAttributes({ [SPAN_ATTRS.CONVERSATION_ID]: conversationId, [SPAN_ATTRS.USER_ID]: userId })

  const { participant } = await props.apiUtils.findParticipant({ id: conversationId, userId: req.auth.userId })

  if (!participant) {
    throw new errors.ForbiddenError("You are not a participant in this message's conversation")
  }

  const { type, payload: mappedPayload } = msgPayload.mapChatMessageToBotpress({ payload, metadata })
  const { message } = await props.client.createMessage({
    type,
    conversationId,
    tags: {},
    userId,
    payload: mappedPayload,
  })

  setSpanAttributes({ [SPAN_ATTRS.MESSAGE_ID]: message.id })

  const res = await fidHandler.mapResponse({
    body: {
      message: model.mapMessage(message),
    },
  })

  await props.signals.emit(conversationId, {
    type: 'message_created',
    data: { ...res.body.message, isBot: false },
  })

  return res
}

export const getMessage: types.AuthenticatedOperations['getMessage'] = async (props, foreignReq) => {
  const fidHandler = fid.handlers.getMessage(props, foreignReq)
  const req = await fidHandler.mapRequest()

  setSpanAttributes({ [SPAN_ATTRS.USER_ID]: req.auth.userId, [SPAN_ATTRS.MESSAGE_ID]: req.params.id })

  const { message } = await props.client.getMessage({ id: req.params.id })
  const { conversationId } = message
  setSpanAttributes({ [SPAN_ATTRS.CONVERSATION_ID]: conversationId })
  const { participant } = await props.apiUtils.findParticipant({ id: conversationId, userId: req.auth.userId })
  if (!participant) {
    throw new errors.ForbiddenError("You are not a participant in this message's conversation")
  }

  return fidHandler.mapResponse({
    body: {
      message: model.mapMessage(message),
    },
  })
}

export const deleteMessage: types.AuthenticatedOperations['deleteMessage'] = async (props, foreignReq) => {
  const fidHandler = fid.handlers.deleteMessage(props, foreignReq)
  const req = await fidHandler.mapRequest()

  const { id } = req.params

  setSpanAttributes({ [SPAN_ATTRS.USER_ID]: req.auth.userId, [SPAN_ATTRS.MESSAGE_ID]: id })

  const { message } = await props.client.getMessage({ id })

  setSpanAttributes({ [SPAN_ATTRS.CONVERSATION_ID]: message.conversationId })

  if (message.userId !== req.auth.userId) {
    throw new errors.ForbiddenError('You are not the sender of this message')
  }

  await props.client.deleteMessage({ id })

  await props.signals.emit(message.conversationId, {
    type: 'message_deleted',
    data: {
      id: message.id,
      conversationId: message.conversationId,
      userId: message.userId,
    },
  })

  return fidHandler.mapResponse({ body: {} })
}
