import React, { useEffect, useState } from 'react';
import {
  ActivityIndicator,
  Alert,
  Clipboard,
  ImageBackground,
  StyleProp,
  StyleSheet,
  Text,
  TextStyle,
  View,
  ViewStyle,
} from 'react-native';
import { Actions as ChatActions, Bubble, BubbleProps, Composer, Day, GiftedChat, MessageText, MessageTextProps, Send, SendProps, Time, TimeProps } from 'react-native-gifted-chat';
import { ICallEvent, IMessage, IRoomEvent, IUrgencyType } from '../../store/messages/types';
import { IFile } from '../../store/sharedFile/types';
import { Logger } from '../../utils/Log';
import { IStyledProps } from '../common/types';
import { eventEmitter, EventType } from '../../services/EventEmitter';
import { Strings } from '../../resources/localization/Strings'
import { deletedMessageView, IStyleHeaderView, IStyleSendingExtraView, messageHeaderView, messageTypesIcon, repliedMessageView, sendingExtraView, systemMessageView } from './MessageUIProvider';
import { ImageHolder, IImageHolderStyle } from '../common/ImageHolder';
import Icon from 'react-native-vector-icons/Ionicons';
import moment from 'moment';
import { messagesService } from '../../services/messages-service';

const logger = new Logger('MessagesView View');
export interface IMessageProps extends IStyledProps<IMessagesStyleProps> {
  messages: IMessage[];
  loading: boolean;
  alwaysShowSend?: boolean;
  loadMore: () => void;
  sendMessage: (message: IMessage, urgency: string, attachedFileUri: string[]) => void;
  replyMessage: (message: IMessage) => void;
  downloadFile: (fileDescriptorId: string) => void;
  onMessageLongPressed?: (context: any, message: IMessage) => void;
  renderSendingExtraView?: () => React.ReactNode;
  renderChatActions?: () => React.ReactNode;
  renderMessageCustomView?: (currentMessage: IMessage) => React.ReactNode;
  renderSystemMessage?: (currentMessage: IMessage) => React.ReactNode;
  renderMessageImage?: (currentMessage: IMessage) => React.ReactNode;
  renderAvatar?: (currentMessage: IMessage) => React.ReactNode;
  onSend?: (message: IMessage) => void;
  onInputTextChanged?: (text: string) => void;
  renderSendButton?: (sendProps: SendProps<IMessage>) => React.ReactNode;
  renderMessageText?: (messageText: MessageTextProps<IMessage>) => React.ReactNode;
  dateCustomStyle?: StyleProp<TextStyle>;
  renderCustomTime?: (timeProps: TimeProps<IMessage>) => React.ReactNode;
  renderBubbleContainer?: (bubbleProps: BubbleProps<IMessage>) => React.ReactNode;
}
export interface IMessagesStyleProps {
  NoDataMessages?: TextStyle;
  container: ViewStyle;
  ImageBackground: ViewStyle;
  chatActionsContainer?: ViewStyle;
  messageTypesIcon: any;
}

enum IMessageOption {
  Copy = 'Copy Text',
  Forward = 'Forward',
  Reply = 'Reply',
  Delete = 'Delete',
  Cancel = 'Cancel',
  Download = 'Download file'
}

export const MessagesView: React.FunctionComponent<IMessageProps> = (
  props: IMessageProps
) => {
  logger.info('MessagesView');

  const [selectedMessage, setSelectedMessage] = useState<IMessage | any>();
  const messagesMergedStyle = { ...defaultStyle, ...props.style };
  const [filesToUpload, setFilesToUpload] = useState<IFile[]>([]);
  const [textInput, setTextInput] = useState<string>('');
  const [downloadedFileIds, setDownloadedFileIds] = useState<string[]>([]);
  const [showActivityIndicator, setShowActivityIndicator] = useState<boolean>(true);

  let onScroll = false;
  useEffect(() => {
    logger.info('useEffect loading')
    // // To fix send attachment without text
    // GiftedChat.defaultProps.text = ' ' as unknown as undefined;
    
    if (props.messages.length > 0) {
      setShowActivityIndicator(false)
    }
    const timer = setTimeout(() => setShowActivityIndicator(false), 2000);
    const downloadResult = eventEmitter.addListener(
      EventType.FileDownloadFinished,
      (eventData: { isSuccess: boolean, fileId: string, errorMsg?: string }) => {
        const filteredIds = downloadedFileIds.filter((id: string) => id !== eventData.fileId);
        setDownloadedFileIds([...filteredIds])
        if (eventData.isSuccess === false) {
          Alert.alert(Strings.failedToDownload, eventData.errorMsg);
        }
      }
    );

    return () => {
      downloadResult.remove();
      clearTimeout(timer);
    }

  }, [props, downloadedFileIds, filesToUpload]);

  const onSend = (messages: IMessage[]) => {
    const message: IMessage | undefined = messages.pop();
    // setShowSend(false);
    if (message) {
      message.text = textInput
      if (props.onSend) {
        return props.onSend(message);
      }
      else {
        if (message.isReplied) {
          message.associatedMsgId = selectedMessage?._id;
          props.replyMessage(message);
        } else {
          message.attachedFile = filesToUpload;
          props.sendMessage(message);
        }

      }
    }
    resetToDefaultValues()
  };

  const resetToDefaultValues = () => {
    setFilesToUpload([]);
    setSelectedMessage(undefined);
  }

  const renderCustomChatFooter = () => {
    if (props.renderSendingExtraView) {
      return props.renderSendingExtraView();
    }
    return (
      <>
        {selectedMessage?.urgency === IUrgencyType.MEDIUM ? sendingExtraView('Send Important...', close, importantMsgViewStyle) : null}
        {selectedMessage?.urgency === IUrgencyType.LOW ? sendingExtraView('Send Information...', close, infoMsgViewStyle) : null}
        {selectedMessage?.isReplied ? sendingExtraView(selectedMessage?.user.name, close, repliedViewStyle, selectedMessage?.text) : null}

      </>
    )
  }

  const close = () => {
    setFilesToUpload([]);
  }

  const renderMessageImage = (Props: MessageImage['props']) => {
    const message = props.messages.find((item) => {
      return item._id === Props.currentMessage!._id
    });
    if (message) {
      if (props.renderMessageImage) {
        return props.renderMessageImage(message);
      }
      else {
        const image = message!.image;
        const downloadedId = downloadedFileIds.find(id => id === message?.fileDescriptorId);
        const showLoadingIndicator = downloadedId !== undefined;
        return (
          <View >
            {message!.image === 'icon' ?
              <Icon
                name="document"
                style={defaultStyle.msgDocument}
              />
              :
              <ImageBackground
                style={messagesMergedStyle.ImageBackground}
                resizeMode={'contain'}
                source={{ uri: image }}
              />
            }
            {showLoadingIndicator && <ActivityIndicator size="large" color="#00ff00" style={defaultStyle.downloadingLoader} />}
          </View>
        );
      }
    }
    return null;
  };


  const onLongPress = (context: any, message: IMessage) => {
    if (props.onMessageLongPressed) {
      return props.onMessageLongPressed(context, message);
    } else {
      const options: IMessageOption[] = [IMessageOption.Reply, IMessageOption.Forward, IMessageOption.Copy];

      if (message.fileDescriptorId) {
        // Incase the message obj have a `fileDescriptorId` this means this msg have file or image!
        options.push(IMessageOption.Download);
      }
      if (message.isSent && !message.isDeleted) {
        // Show delete option only for the sent msg
        options.push(IMessageOption.Delete);
      }
      options.push(IMessageOption.Cancel);
      const cancelButtonIndex = options.length - 1;
      context.actionSheet().showActionSheetWithOptions(
        {
          options,
          cancelButtonIndex,
        },
        (buttonIndex: number) => {
          switch (options[buttonIndex]) {
            case IMessageOption.Copy:
              Clipboard.setString(message.text);
              break;
            case IMessageOption.Download:
              downloadedFileIds.push(message.fileDescriptorId)
              setDownloadedFileIds([...downloadedFileIds])
              props.downloadFile(message.fileDescriptorId);
              break;
            case IMessageOption.Reply:
              message.isReplied = true;
              setSelectedMessage(message);
              break;
              case IMessageOption.Delete:
            messagesService.deleteMessage(message._id);
            break;
            default:
              break;
          }
        }
      );
    }

  };


  const renderActions = () => {
    if (props.renderChatActions) {
      return props.renderChatActions();
    }
    else {
      return <React.Fragment>
        <ChatActions
          containerStyle={defaultStyle.msgTypeActionContainerStyle}
          icon={messageTypesIcon}
          options={{
            'Important msg': () => {
              const msg = {
                urgency: IUrgencyType.MEDIUM
              }
              setSelectedMessage(msg);
            },
            'Information msg': () => {
              const msg = {
                urgency: IUrgencyType.LOW
              }
              setSelectedMessage(msg);
            },
            Cancel: () => {
              console.log('Cancel');
            },
          }}
        />
      </React.Fragment>
    }
  };

  const renderEmptyChat = () => {
    return (
      <View
        style={defaultStyle.NoDataMessages}>
        <Text> No messages available</Text>
      </View>
    )
  }
  const onTextInputChanges = (text: string) => {
    if (props.onInputTextChanged) {
      props.onInputTextChanged(text);
    }
    setTextInput(text);
  }

  const renderComposer = (prop: any) => {
    return (
      <Composer
        {...prop}
        placeholder="Type a message..."
        text={textInput}
      />
    );
  }

  const renderAvatar = (Props: Avatar['props']) => {
    const currentMsg = props.messages.find((item) => {
      return item._id === Props.currentMessage!._id
    });
    if (currentMsg) {
      if (props.renderAvatar) {
        return props.renderAvatar(currentMsg);
      }
      else {
        const { user } = currentMsg;
        return (
          <ImageHolder url={user.avatar} name={user.name} style={senderAvatarStyle} />
        );
      }
    }
    return null;
  }

  const renderSystemMessage = (Props: any) => {
    if (props.renderSystemMessage) {
      return props.renderSystemMessage(Props.currentMessage);
    }
    else {
      const conference = Props.currentMessage.conference;
      const call: ICallEvent = Props.currentMessage.call;
      const roomEvent: IRoomEvent = Props.currentMessage.roomEvent;
      if (conference) {
        return systemMessageView(conference.msgContent);
      }
      else if (call) {
        return systemMessageView(call.msgContent);
      }
      else if (roomEvent) {
        return systemMessageView(roomEvent.msgContent);
      }
      else {
        return;
      }
    }

  }
  const renderCustomMessageText = (Props: MessageTextProps<IMessage>) => {
    if (props.renderMessageText) {
      return props.renderMessageText(Props)
    }
    else {
      return <MessageText  {...Props} />
    }
  }
  const renderCustomView = (Props: any) => {
    const currentMessage = Props.currentMessage;

    if (props.renderMessageCustomView)
      return props.renderMessageCustomView(currentMessage);

    const filterMessage: IMessage[] = props.messages.filter(data => data._id === currentMessage.associatedMsgId);
    const warningIcon = <Icon name="warning" />;
    const infoIcon = <Icon name="information-circle-outline" />;
    const arrowForwardIcon = <Icon name="arrow-forward-circle-outline" size={25} />;

    return (
      <>
        {currentMessage.urgency === IUrgencyType.MEDIUM ? messageHeaderView(warningIcon, importantHeaderViewStyle, Strings.Important) : null}
        {currentMessage.urgency === IUrgencyType.LOW ? messageHeaderView(infoIcon, infoHeaderViewStyle, Strings.Information) : null}
        {currentMessage.isDeleted ? deletedMessageView() : null}
        {(currentMessage.isReplied && filterMessage.length > 0) ? repliedMessageView(filterMessage[0].text, filterMessage[0].user.name, null) : null}
        {currentMessage.isForwarded ? messageHeaderView(arrowForwardIcon, forwardHeaderViewStyle, Strings.Forwarded) : null}

      </>
    )
  }

  const loadMore = () => {
    if (!onScroll) return;
    setShowActivityIndicator(true)
    props.loadMore();
    onScroll = false
  }

  const shouldUpdateMessage = () => {
    return true
  }
  const shouldShowSendButton = () => {
    if (props.alwaysShowSend) {
      return props.alwaysShowSend;
    }
    return true
  }

  const renderSend = (sendProps: SendProps<IMessage>) => {
    if (props.renderSendButton) {
      return (
        <Send
          {...sendProps}
          disabled={!sendProps.text}
        >
          {props.renderSendButton(sendProps)}
        </Send>
      );
    }
    return <Send  {...sendProps} />;

  };
  const renderCustomDay = (Props: Day['props']) => {
    if (props.dateCustomStyle)
      return <Day {...Props} textStyle={props.dateCustomStyle} />
    else
      return (
        <View style={defaultStyle.customDateView}>
        <Text style={defaultStyle.customDateFont}>
          {moment(Props.currentMessage?.createdAt, 'ddd MMM DD HH:mm:ss YYYY').format('MMM DD, YYYY')}
        </Text>
      </View>)
  }
  const renderCustomTime = (timeProps: TimeProps<IMessage>) => {
    if (props.renderCustomTime)
      return props.renderCustomTime(timeProps)
    else
      return <Time {...timeProps} />

  }
  /**
   * @name renderUsername
   * @param bubblesProps 
   * @description 
   * function uses this helper function to determine if the username should be displayed in the bubble chat.
   * If the previous message's user is different from the current user and the current message is not sent by the current user,
   *  the username will be displayed. Otherwise, it will return null.
   */
  const renderUsername = (bubblesProps: BubbleProps<IMessage>) => {
    const { previousMessage, currentMessage } = bubblesProps;

    if (previousMessage?.user && !isCurrentUserMessage(bubblesProps)) {
      const isSameUserInPrevMessage = previousMessage.user._id === currentMessage?.user._id;
      return !isSameUserInPrevMessage && currentMessage?.user.name;
    }
    return null;
  };

  /**
   * @name isCurrentUserMessage
   * @param props 
   * @description 
   *  checks if the current message (currentMessage) is sent by the current user (user).
   *  If it is, the function will return true,indicating that the current message belongs to the current user.
   */
  const isCurrentUserMessage = (msgProps: BubbleProps<IMessage>) => {
    const { currentMessage, user } = msgProps;
    return currentMessage?.user._id === user?._id;
  };

  const renderBubbleContainer = (bubblesProps: BubbleProps<IMessage>) => {
    const { currentMessage } = bubblesProps;
    const date = currentMessage?.createdAt
      ? moment(currentMessage.createdAt, 'ddd MMM DD HH:mm:ss YYYY').format('HH:mm') // Adjust format
      : 'Invalid Date';
    if (props.renderBubbleContainer) {
      return props.renderBubbleContainer(bubblesProps)
    }
    else {
      return (
        <View style={{ flex: 1, flexDirection: 'column' }} >
          <Text style={defaultStyle.username}>{renderUsername(bubblesProps)}</Text>
          {/* <Bubble {...bubblesProps} /> */}
          <Bubble
            {...bubblesProps}
            wrapperStyle={{
             
              left: { backgroundColor: '#f0f0f0', padding:5 },
              right: { backgroundColor: '#0084ff', padding:5 },
            }}
            renderTime={() => (
              <Text style={{ color: 'gray', fontSize: 10 }}>{date}</Text>
            )}
          />
        </View>
      )
    }
  }


  return (
    <View style={defaultStyle.messageContainer}>
      {showActivityIndicator && <ActivityIndicator size="large" color="blue" />}
      <GiftedChat
        messages={props.messages}
        onSend={onSend}
        user={{
          _id: 'sent',
        }}
        renderChatFooter={renderCustomChatFooter}
        renderMessageImage={renderMessageImage}
        onLongPress={onLongPress}
        renderAvatar={renderAvatar}
        renderActions={renderActions}
        renderChatEmpty={renderEmptyChat}
        renderComposer={renderComposer}
        renderCustomView={renderCustomView}
        onInputTextChanged={onTextInputChanges}
        alwaysShowSend={shouldShowSendButton()}
        renderSystemMessage={renderSystemMessage}
        shouldUpdateMessage={shouldUpdateMessage}
        listViewProps={{
          onMomentumScrollBegin: () => {
            loadMore()
          },
          onEndReached: () => {
            onScroll = true;
          }
        }}
        renderSend={renderSend}
        renderMessageText={renderCustomMessageText}
        renderDay={renderCustomDay}
        renderTime={renderCustomTime}
        renderBubble={renderBubbleContainer}
      />
    </View>
  );
};


const repliedViewStyle: IStyleSendingExtraView = StyleSheet.create({
  containerStyle: { padding: 10, backgroundColor: '#fdeed9', borderRadius: 10 },
  textStyle: { color: '#e3902b', fontWeight: 'bold', fontSize: 15 },
  msgStyle: { fontSize: 15 },
});
const infoMsgViewStyle: IStyleSendingExtraView = StyleSheet.create({
  containerStyle: { backgroundColor: '#cae1fb', minHeight: 40, padding: 10 },
  textStyle: { color: '#3f8df5' },
});
const importantMsgViewStyle: IStyleSendingExtraView = StyleSheet.create({
  containerStyle: { backgroundColor: '#f9d38b', minHeight: 40, padding: 10 },
  textStyle: { color: '#c85c2c' },
});
const importantHeaderViewStyle: IStyleHeaderView = StyleSheet.create({
  containerStyle: { backgroundColor: '#f9d38b', borderRadius: 10, width: '100%', alignContent: 'center', flexDirection: 'row', padding: 5 },
  iconStyle: { color: '#c85c2c' },
  textStyle: { color: '#c85c2c', fontSize: 15, paddingTop: 10, paddingBottom: 10 }
});
const infoHeaderViewStyle: IStyleHeaderView = StyleSheet.create({
  containerStyle: { backgroundColor: '#cae1fb', borderRadius: 10, width: '100%', alignContent: 'center', flexDirection: 'row', padding: 5 },
  iconStyle: { color: '#3f8df5' },
  textStyle: { color: '#3f8df5', fontSize: 15, paddingTop: 10, paddingBottom: 10 }
});


const defaultStyle = StyleSheet.create({
  msgTypeActionContainerStyle: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', marginBottom: 0, marginLeft: 4, marginRight: 4 },
  attachActionContainerStyle: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', marginBottom: 0, marginLeft: -15 },
  filesToUploadContainer: { backgroundColor: '#DCDCDC', minHeight: 40, padding: 10, flexDirection: 'row' },
  messageContainer: { flex: 1 },
  NoDataMessages: { flex: 1, alignSelf: 'center', justifyContent: 'center', transform: [{ scaleY: -1 }] },
  msgDocument: { margin: 20, fontSize: 50, color: 'red' },
  downloadingLoader: { position: 'absolute', top: '50%', left: '50%' },
  container: { flex: 1, backgroundColor: '#ffffff', height: 'auto', },
  ImageBackground: { width: '100%', aspectRatio: 1, height: undefined },
  chatActionsContainer: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', marginBottom: 0, marginLeft: 4, marginRight: 4 },
  messageTypesIcon: { fontSize: 35, color: '#3f8df5' },
  customDateView: { alignItems: 'center', marginTop: 10 },
  customDateFont: { color: 'grey', fontSize: 12 },
  username: {fontSize: 12,  marginLeft: 10,  fontWeight: 'bold' }
});

const senderAvatarStyle: IImageHolderStyle = StyleSheet.create({
  imageTextStyle: { color: 'white', fontSize: 15, fontWeight: 'bold' },
  thumbnailContainer: {
    justifyContent: 'center',
    alignItems: 'center',
    width: 40,
    height: 40,
    borderRadius: 20,
  },
  thumbnail: {
    width: 40,
    height: 40,
    borderRadius: 20,
  }
});