import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Meteor } from 'meteor/meteor';
import { defineMessages, injectIntl } from 'react-intl';
import injectNotify from '/imports/ui/components/common/toast/inject-notify/component';
import AudioService from '/imports/ui/components/audio/service';
import ChatPushAlert from './push-alert/component';
import { stripTags, unescapeHtml, uniqueId } from '/imports/utils/string-utils';
import Service from '../service';
import Styled from './styles';
import { usePreviousValue } from '/imports/ui/components/utils/hooks';
import { Session } from 'meteor/session';
import { isEqual } from 'radash';

const CHAT_CONFIG = Meteor.settings.public.chat;
const PUBLIC_CHAT_CLEAR = CHAT_CONFIG.chat_clear;
const PUBLIC_CHAT_ID = CHAT_CONFIG.public_id;
const POLL_RESULT_KEY = CHAT_CONFIG.system_messages_keys.chat_poll_result;
const EXPORTED_PRESENTATION_KEY = CHAT_CONFIG.system_messages_keys.chat_exported_presentation;

const propTypes = {
  pushAlertEnabled: PropTypes.bool.isRequired,
  audioAlertEnabled: PropTypes.bool.isRequired,
  unreadMessagesCountByChat: PropTypes.arrayOf(PropTypes.object),
  unreadMessagesByChat: PropTypes.arrayOf(PropTypes.array),
  idChatOpen: PropTypes.string.isRequired,
  intl: PropTypes.shape({
    formatMessage: PropTypes.func.isRequired,
  }).isRequired,
};

const defaultProps = {
  unreadMessagesCountByChat: null,
  unreadMessagesByChat: null,
};

const intlMessages = defineMessages({
  appToastChatPublic: {
    id: 'app.toast.chat.public',
    description: 'when entry various message',
  },
  appToastChatPrivate: {
    id: 'app.toast.chat.private',
    description: 'when entry various message',
  },
  appToastChatSystem: {
    id: 'app.toast.chat.system',
    description: 'system for use',
  },
  publicChatClear: {
    id: 'app.chat.clearPublicChatMessage',
    description: 'message of when clear the public chat',
  },
  publicChatMsg: {
    id: 'app.toast.chat.public',
    description: 'public chat toast message title',
  },
  privateChatMsg: {
    id: 'app.toast.chat.private',
    description: 'private chat toast message title',
  },
  pollResults: {
    id: 'app.toast.chat.poll',
    description: 'chat toast message for polls',
  },
  pollResultsClick: {
    id: 'app.toast.chat.pollClick',
    description: 'chat toast click message for polls',
  },
  exportedPresentation: {
    id: 'app.toast.chat.exportedPresentation',
    description: 'chat toast message for exportedPresentation',
  }
});

const ALERT_INTERVAL = 5000; // 5 seconds
const ALERT_DURATION = 4000; // 4 seconds

const ChatAlert = (props) => {
  const {
    audioAlertEnabled,
    pushAlertEnabled,
    idChatOpen,
    unreadMessagesCountByChat,
    unreadMessagesByChat,
    intl,
    layoutContextDispatch,
  } = props;

  const [unreadMessagesCount, setUnreadMessagesCount] = useState(0);
  const [unreadMessages, setUnreadMessages] = useState([]);
  const [lastAlertTimestampByChat, setLastAlertTimestampByChat] = useState({});
  const [alertEnabledTimestamp, setAlertEnabledTimestamp] = useState(null);
  const prevUnreadMessages = usePreviousValue(unreadMessages);

  // audio alerts
  useEffect(() => {
    if (audioAlertEnabled) {
      const unreadObject = unreadMessagesCountByChat;

      const unreadCount = document.hidden
        ? unreadObject.reduce((a, b) => a + b.unreadCounter, 0)
        : unreadObject.filter((chat) => chat.chatId !== idChatOpen)
          .reduce((a, b) => a + b.unreadCounter, 0);

      if (unreadCount > unreadMessagesCount) {
        AudioService.playAlertSound(`${Meteor.settings.public.app.cdn
          + Meteor.settings.public.app.basename
          + Meteor.settings.public.app.instanceId}`
          + '/resources/sounds/notify.mp3');
      }

      setUnreadMessagesCount(unreadCount);
    }
  }, [unreadMessagesCountByChat]);

  // push alerts
  useEffect(() => {
    if (pushAlertEnabled) {
      setAlertEnabledTimestamp(new Date().getTime());
    }
  }, [pushAlertEnabled]);

  useEffect(() => {
    if (pushAlertEnabled) {
      const alertsObject = unreadMessagesByChat;

      let timewindowsToAlert = [];
      let filteredTimewindows = [];

      alertsObject.forEach((chat) => {
        filteredTimewindows = filteredTimewindows.concat(
          chat.filter((timeWindow) => timeWindow.timestamp > alertEnabledTimestamp),
        );
      });

      filteredTimewindows.forEach((timeWindow) => {
        const durationDiff = ALERT_DURATION - (new Date().getTime() - timeWindow.timestamp);

        if ((timeWindow.lastTimestamp > timeWindow.timestamp && durationDiff > 0
          && timeWindow.lastTimestamp > (lastAlertTimestampByChat[timeWindow.chatId] || 0))
          || timeWindow.timestamp
          > (lastAlertTimestampByChat[timeWindow.chatId] || 0) + ALERT_INTERVAL) {
          timewindowsToAlert = timewindowsToAlert
            .filter((item) => item.chatId !== timeWindow.chatId);
          const newTimeWindow = { ...timeWindow };
          newTimeWindow.durationDiff = durationDiff;
          timewindowsToAlert.push(newTimeWindow);

          const newLastAlertTimestampByChat = { ...lastAlertTimestampByChat };
          if (timeWindow.timestamp > (lastAlertTimestampByChat[timeWindow.chatId] || 0)) {
            newLastAlertTimestampByChat[timeWindow.chatId] = timeWindow.timestamp;
            setLastAlertTimestampByChat(newLastAlertTimestampByChat);
          }
        }
      });
      setUnreadMessages(timewindowsToAlert);
    }
  }, [unreadMessagesByChat]);

  const mapContentText = (message) => {
    const contentMessage = message
      .map((content) => {
        if (content.text === PUBLIC_CHAT_CLEAR) {
          return intl.formatMessage(intlMessages.publicChatClear);
        }

        return unescapeHtml(stripTags(content.text));
      });

    return contentMessage;
  };

  const createMessage = (name, message) => (
    <Styled.PushMessageContent>
      <Styled.UserNameMessage>{name}</Styled.UserNameMessage>
      <Styled.ContentMessage>
        {
          mapContentText(message)
            .reduce((acc, text) => [...acc, (<br key={uniqueId('br_')} />), text], [])
        }
      </Styled.ContentMessage>
    </Styled.PushMessageContent>
  );

  const createPollMessage = () => (
    <Styled.PushMessageContent>
      <Styled.UserNameMessage>
        {intl.formatMessage(intlMessages.pollResults)}
      </Styled.UserNameMessage>
      <Styled.ContentMessagePoll>
        {intl.formatMessage(intlMessages.pollResultsClick)}
      </Styled.ContentMessagePoll>
    </Styled.PushMessageContent>
  );

  const createExportedPresentationMessage = (filename) => (
    <Styled.PushMessageContent>
      <Styled.UserNameMessage>{intl.formatMessage(intlMessages.exportedPresentation)}</Styled.UserNameMessage>
      <Styled.ContentMessageExportedPresentation>{filename}</Styled.ContentMessageExportedPresentation>
    </Styled.PushMessageContent>
  );

  if (isEqual(prevUnreadMessages, unreadMessages)) {
    return null;
  }

  return pushAlertEnabled
    ? unreadMessages.map((timeWindow) => {
      const mappedMessage = Service.mapGroupMessage(timeWindow);

      let content = null;
      let isPollResult = false;
      if (mappedMessage) {
        if (mappedMessage.id.includes(POLL_RESULT_KEY)) {
          content = createPollMessage();
          isPollResult = true;
        } else if (mappedMessage.id.includes(EXPORTED_PRESENTATION_KEY)) {
          content = createExportedPresentationMessage(mappedMessage.extra.filename);
        } else {
          content = createMessage(mappedMessage.sender.name, mappedMessage.content.slice(-5));
        }
      }

      const messageChatId = mappedMessage.chatId === 'MAIN-PUBLIC-GROUP-CHAT' ? PUBLIC_CHAT_ID : mappedMessage.chatId;

      const newUnreadMessages = unreadMessages
        .filter((message) => message.key !== mappedMessage.key);

      return content
        ? (
          <ChatPushAlert
            key={messageChatId}
            chatId={messageChatId}
            content={content}
            title={
              (mappedMessage.chatId === 'MAIN-PUBLIC-GROUP-CHAT')
                ? <span>{intl.formatMessage(intlMessages.appToastChatPublic)}</span>
                : <span>{intl.formatMessage(intlMessages.appToastChatPrivate)}</span>
            }
            onOpen={
              () => {
                if (isPollResult) {
                  Session.set('ignorePollNotifications', true);
                }

                setUnreadMessages(newUnreadMessages);
              }
            }
            onClose={
              () => {
                if (isPollResult) {
                  Session.set('ignorePollNotifications', false);
                }

                setUnreadMessages(newUnreadMessages);
              }
            }
            alertDuration={timeWindow.durationDiff}
            layoutContextDispatch={layoutContextDispatch}
          />
        ) : null;
    })
    : null;
};
ChatAlert.propTypes = propTypes;
ChatAlert.defaultProps = defaultProps;

export default injectNotify(injectIntl(ChatAlert));
