import React, { useEffect, useMemo, useRef } from 'react'
import { ChatMessageModel, useChat, selectRemoteParticipants, selectLocalParticipantIsConnected } from '../../store'
import { useZocksStore } from '../../app'
import { useZocksDispatch } from '../../app/hooks'
import { setMessageRecipient } from '../../store/chat/chatSlice'
import { ChatProps } from './models'
import { CustomizableChatInput } from './ChatInput'
import { ChatMessageWithParticipantInfo } from './ChatMessage'
import { getClassName, getMergedClassNames } from '../common'
import zocksStyle from './Chat.module.scss'
import { ParticipantNotConnected } from './ParticipantNotConnected'

export const CombinedChat: React.FC<ChatProps> = ({ styles, chatActions, dismiss, components }) => {
  const dispatch = useZocksDispatch()
  const {
    sendPublicMessage,
    sendPrivateMessage,
    uploadAttachment,
    getAttachmentLocation,
    publicChatMessages,
    privateChatMessages,
    messageRecipient,
  } = useChat(chatActions)
  const localParticipantIsConnected = useZocksStore(selectLocalParticipantIsConnected)
  const remoteParticipants = useZocksStore(selectRemoteParticipants)

  const messagesEndRef = useRef<HTMLDivElement>(null)
  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
  }

  const allChatMessages = useMemo(
    () =>
      [...publicChatMessages, ...Object.values(privateChatMessages).flat()].sort((a, b) => a.timestamp - b.timestamp),
    [publicChatMessages, privateChatMessages]
  )

  useEffect(() => {
    scrollToBottom()
  }, [allChatMessages])

  const sameSenderAndRecipient = (message: ChatMessageModel, other: ChatMessageModel): boolean => {
    const {
      from: { id: messageSenderId },
      to: { id: messageRecipientId } = {},
    } = message
    const {
      from: { id: otherSenderId },
      to: { id: otherRecipientId } = {},
    } = other
    return messageSenderId === otherSenderId && messageRecipientId === otherRecipientId
  }

  const handleRecipientSelected = (recipientId: string) => {
    dispatch(setMessageRecipient(recipientId))
  }

  const ChatMessageElement = components?.ChatMessage ?? ChatMessageWithParticipantInfo
  const ChatInputElement = components?.ChatInput ?? CustomizableChatInput
  const ParticipantNotConnectedElement = components?.ParticipantNotConnected ?? ParticipantNotConnected
  const mergedStyles = getMergedClassNames(zocksStyle, styles)

  if (!localParticipantIsConnected) {
    return <ParticipantNotConnectedElement styles={mergedStyles} />
  }

  return (
    <div className={getClassName('chat', mergedStyles)}>
      {dismiss && (
        <div className={getClassName('chat__header', mergedStyles)}>
          <button
            className={getClassName('chat__header-dismiss-button', mergedStyles)}
            onClick={dismiss}
            aria-label='Dismiss'
          />
        </div>
      )}
      <div className={getClassName('chat__main-container', mergedStyles)}>
        <div className={getClassName('chat__messages-container', mergedStyles)}>
          <div className={getClassName('chat__messages-scroll', mergedStyles)}>
            {allChatMessages.map((chatMessage, idx) => {
              const showParticipantInfo =
                idx === 0 || !sameSenderAndRecipient(allChatMessages[idx], allChatMessages[idx - 1])
              return (
                <ChatMessageElement
                  key={idx}
                  chatMessage={chatMessage}
                  showParticipantInfo={showParticipantInfo}
                  getAttachmentLocation={getAttachmentLocation}
                  styles={mergedStyles}
                />
              )
            })}
            <div ref={messagesEndRef} />
          </div>
        </div>
        <div className={getClassName('chat__footer', mergedStyles)}>
          <ChatInputElement
            messageRecipient={messageRecipient}
            onRecipientSelected={handleRecipientSelected}
            remoteParticipants={remoteParticipants}
            sendPublicMessage={sendPublicMessage}
            sendPrivateMessage={sendPrivateMessage}
            uploadAttachment={uploadAttachment}
            styles={mergedStyles}
          />
        </div>
      </div>
    </div>
  )
}
