<script setup>
import { defineProps, computed, ref } from 'vue';
import Message from './Message.vue';
import { MESSAGE_TYPES } from './constants.js';
import { useCamelCase } from 'dashboard/composables/useTransformKeys';
import { useMapGetter, useStore } from 'dashboard/composables/store.js';

/**
 * Props definition for the component
 * @typedef {Object} Props
 * @property {Array} readMessages - Array of read messages
 * @property {Array} unReadMessages - Array of unread messages
 * @property {Number} currentUserId - ID of the current user
 * @property {Boolean} isAnEmailChannel - Whether this is an email channel
 * @property {Object} inboxSupportsReplyTo - Inbox reply support configuration
 * @property {Array} messages - Array of all messages [These are not in camelcase]
 */
const props = defineProps({
  currentUserId: {
    type: Number,
    required: true,
  },
  firstUnreadId: {
    type: Number,
    default: null,
  },
  isAnEmailChannel: {
    type: Boolean,
    default: false,
  },
  inboxSupportsReplyTo: {
    type: Object,
    default: () => ({ incoming: false, outgoing: false }),
  },
  messages: {
    type: Array,
    default: () => [],
  },
});

const emit = defineEmits(['retry']);
const store = useStore();

const fetchingConversations = ref(new Set());
const allMessages = computed(() => {
  return useCamelCase(props.messages, { deep: true });
});

const currentChat = useMapGetter('getSelectedChat');

/**
 * Determines if a message should be grouped with the next message
 * @param {Number} index - Index of the current message
 * @param {Array} searchList - Array of messages to check
 * @returns {Boolean} - Whether the message should be grouped with next
 */
const shouldGroupWithNext = (index, searchList) => {
  if (index === searchList.length - 1) return false;

  const current = searchList[index];
  const next = searchList[index + 1];

  if (next.status === 'failed') return false;

  const nextSenderId = next.senderId ?? next.sender?.id;
  const currentSenderId = current.senderId ?? current.sender?.id;
  const hasSameSender = nextSenderId === currentSenderId;

  const nextMessageType = next.messageType;
  const currentMessageType = current.messageType;

  const areBothTemplates =
    nextMessageType === MESSAGE_TYPES.TEMPLATE &&
    currentMessageType === MESSAGE_TYPES.TEMPLATE;

  if (!hasSameSender || areBothTemplates) return false;

  if (currentMessageType !== nextMessageType) return false;

  // Check if messages are in the same minute by rounding down to nearest minute
  return Math.floor(next.createdAt / 60) === Math.floor(current.createdAt / 60);
};

/**
 * Gets the message that was replied to
 * @param {Object} parentMessage - The message containing the reply reference
 * @returns {Object|null} - The message being replied to, or null if not found
 */
const getInReplyToMessage = parentMessage => {
  const inReplyToMessageId =
    parentMessage?.contentAttributes?.inReplyTo ??
    parentMessage?.content_attributes?.in_reply_to;

  if (!inReplyToMessageId) return null;

  // 1. Check props messages (already camelCased via allMessages)
  const foundInProps = allMessages.value?.find(
    m => m.id === inReplyToMessageId
  );
  if (foundInProps) return foundInProps;

  // 2. Check store messages
  const foundInStore = currentChat.value?.messages?.find(
    m => m.id === inReplyToMessageId
  );
  if (foundInStore) return useCamelCase(foundInStore);

  // 3. Fetch if not currently fetching for this conversation
  const conversationId = currentChat.value?.id;
  if (
    conversationId &&
    !currentChat.value.allMessagesLoaded &&
    !fetchingConversations.value.has(conversationId)
  ) {
    fetchingConversations.value.add(conversationId);
    store
      .dispatch('fetchPreviousMessages', {
        conversationId,
        before: currentChat.value.messages?.[0]?.id ?? null,
      })
      .finally(() => {
        fetchingConversations.value.delete(conversationId);
      });
  }

  return null;
};
</script>

<template>
  <ul class="px-4 bg-n-background">
    <slot name="beforeAll" />
    <template v-for="(message, index) in allMessages" :key="message.id">
      <slot
        v-if="firstUnreadId && message.id === firstUnreadId"
        name="unreadBadge"
      />
      <Message
        v-bind="message"
        :is-email-inbox="isAnEmailChannel"
        :in-reply-to="getInReplyToMessage(message)"
        :group-with-next="shouldGroupWithNext(index, allMessages)"
        :inbox-supports-reply-to="inboxSupportsReplyTo"
        :current-user-id="currentUserId"
        data-clarity-mask="True"
        @retry="emit('retry', message)"
      />
    </template>
    <slot name="after" />
  </ul>
</template>
