import React, { useEffect, useState } from 'react';
import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon';
import { Avatar, AvatarSize } from '../../Avatar';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton';
import { SessionDropdown } from '../SessionDropdown';
import { MediaGallery } from '../../conversation/media-gallery/MediaGallery';
import _ from 'lodash';
import { Constants } from '../../../session';
import { AttachmentTypeWithPath } from '../../../types/Attachment';
import { useTheme } from 'styled-components';
import {
  getMessagesWithFileAttachments,
  getMessagesWithVisualMediaAttachments,
} from '../../../data/data';
import { SpacerLG } from '../../basic/Text';
import {
  deleteMessagesByConvoIdWithConfirmation,
  setDisappearingMessagesByConvoId,
  showAddModeratorsByConvoId,
  showInviteContactByConvoId,
  showLeaveGroupByConvoId,
  showRemoveModeratorsByConvoId,
  showUpdateGroupMembersByConvoId,
  showUpdateGroupNameByConvoId,
} from '../../../interactions/conversationInteractions';
import { MediaItemType } from '../../LightboxGallery';
// tslint:disable-next-line: no-submodule-imports
import useInterval from 'react-use/lib/useInterval';
import { useDispatch, useSelector } from 'react-redux';
import { getTimerOptions } from '../../../state/selectors/timerOptions';
import {
  getSelectedConversation,
  isRightPanelShowing,
} from '../../../state/selectors/conversations';
import { useMembersAvatars } from '../../../hooks/useMembersAvatar';
import { closeRightPanel } from '../../../state/ducks/conversations';

async function getMediaGalleryProps(
  conversationId: string
): Promise<{
  documents: Array<MediaItemType>;
  media: Array<MediaItemType>;
}> {
  // We fetch more documents than media as they don’t require to be loaded
  // into memory right away. Revisit this once we have infinite scrolling:
  const rawMedia = await getMessagesWithVisualMediaAttachments(conversationId, {
    limit: Constants.CONVERSATION.DEFAULT_MEDIA_FETCH_COUNT,
  });
  const rawDocuments = await getMessagesWithFileAttachments(conversationId, {
    limit: Constants.CONVERSATION.DEFAULT_DOCUMENTS_FETCH_COUNT,
  });

  const media = _.flatten(
    rawMedia.map(attributes => {
      const { attachments, source, id, timestamp, serverTimestamp, received_at } = attributes;

      return (attachments || [])
        .filter(
          (attachment: AttachmentTypeWithPath) =>
            attachment.thumbnail && !attachment.pending && !attachment.error
        )
        .map((attachment: AttachmentTypeWithPath, index: number) => {
          const { thumbnail } = attachment;

          const mediaItem: MediaItemType = {
            objectURL: window.Signal.Migrations.getAbsoluteAttachmentPath(attachment.path),
            thumbnailObjectUrl: thumbnail
              ? window.Signal.Migrations.getAbsoluteAttachmentPath(thumbnail.path)
              : null,
            contentType: attachment.contentType || '',
            index,
            messageTimestamp: timestamp || serverTimestamp || received_at || 0,
            messageSender: source,
            messageId: id,
            attachment,
          };

          return mediaItem;
        });
    })
  );

  // Unlike visual media, only one non-image attachment is supported
  const documents = rawDocuments.map(attributes => {
    // this is to not fail if the attachment is invalid (could be a Long Attachment type which is not supported)
    if (!attributes.attachments?.length) {
      // window?.log?.info(
      //   'Got a message with an empty list of attachment. Skipping...'
      // );
      return null;
    }
    const attachment = attributes.attachments[0];
    const { source, id, timestamp, serverTimestamp, received_at } = attributes;

    return {
      contentType: attachment.contentType,
      index: 0,
      attachment,
      messageTimestamp: timestamp || serverTimestamp || received_at || 0,
      messageSender: source,
      messageId: id,
    };
  });

  return {
    media,
    documents: _.compact(documents), // remove null
  };
}

const HeaderItem = () => {
  const selectedConversation = useSelector(getSelectedConversation);
  const theme = useTheme();
  const dispatch = useDispatch();
  const memberDetails = useMembersAvatars(selectedConversation);

  if (!selectedConversation) {
    return null;
  }
  const {
    avatarPath,
    id,
    isGroup,
    isKickedFromGroup,
    profileName,
    phoneNumber,
    isBlocked,
    left,
    name,
  } = selectedConversation;

  const showInviteContacts = isGroup && !isKickedFromGroup && !isBlocked && !left;
  const userName = name || profileName || phoneNumber;

  return (
    <div className="group-settings-header">
      <SessionIconButton
        iconType={SessionIconType.Chevron}
        iconSize={SessionIconSize.Medium}
        iconRotation={270}
        onClick={() => {
          dispatch(closeRightPanel());
        }}
        theme={theme}
      />
      <Avatar
        avatarPath={avatarPath || ''}
        name={userName}
        size={AvatarSize.XL}
        memberAvatars={memberDetails}
        pubkey={id}
      />
      <div className="invite-friends-container">
        {showInviteContacts && (
          <SessionIconButton
            iconType={SessionIconType.AddUser}
            iconSize={SessionIconSize.Medium}
            onClick={() => {
              if (selectedConversation) {
                showInviteContactByConvoId(selectedConversation.id);
              }
            }}
            theme={theme}
          />
        )}
      </div>
    </div>
  );
};

// tslint:disable: cyclomatic-complexity
// tslint:disable: max-func-body-length
export const SessionRightPanelWithDetails = () => {
  const [documents, setDocuments] = useState<Array<MediaItemType>>([]);
  const [media, setMedia] = useState<Array<MediaItemType>>([]);

  const selectedConversation = useSelector(getSelectedConversation);
  const isShowing = useSelector(isRightPanelShowing);

  useEffect(() => {
    let isRunning = true;

    if (isShowing && selectedConversation) {
      void getMediaGalleryProps(selectedConversation.id).then(results => {
        if (isRunning) {
          if (!_.isEqual(documents, results.documents)) {
            setDocuments(results.documents);
          }

          if (!_.isEqual(media, results.media)) {
            setMedia(results.media);
          }
        }
      });
    }

    return () => {
      isRunning = false;
      return;
    };
  }, [isShowing, selectedConversation?.id]);

  useInterval(async () => {
    if (isShowing && selectedConversation) {
      const results = await getMediaGalleryProps(selectedConversation.id);
      if (results.documents.length !== documents.length || results.media.length !== media.length) {
        setDocuments(results.documents);
        setMedia(results.media);
      }
    }
  }, 10000);

  if (!selectedConversation) {
    return null;
  }

  const {
    id,
    subscriberCount,
    name,
    isKickedFromGroup,
    left,
    isPublic,
    weAreAdmin,
    isBlocked,
    isGroup,
  } = selectedConversation;
  const showMemberCount = !!(subscriberCount && subscriberCount > 0);
  const commonNoShow = isKickedFromGroup || left || isBlocked;
  const hasDisappearingMessages = !isPublic && !commonNoShow;
  const leaveGroupString = isPublic
    ? window.i18n('leaveGroup')
    : isKickedFromGroup
    ? window.i18n('youGotKickedFromGroup')
    : left
    ? window.i18n('youLeftTheGroup')
    : window.i18n('leaveGroup');

  const timerOptions = useSelector(getTimerOptions).timerOptions;

  const disappearingMessagesOptions = timerOptions.map(option => {
    return {
      content: option.name,
      onClick: () => {
        void setDisappearingMessagesByConvoId(id, option.value);
      },
    };
  });

  const showUpdateGroupNameButton =
    isGroup && (!isPublic || (isPublic && weAreAdmin)) && !commonNoShow;
  const showAddRemoveModeratorsButton = weAreAdmin && !commonNoShow && isPublic;
  const showUpdateGroupMembersButton = !isPublic && isGroup && !commonNoShow;

  const deleteConvoAction = isPublic
    ? () => {
        deleteMessagesByConvoIdWithConfirmation(id);
      }
    : () => {
        showLeaveGroupByConvoId(id);
      };
  return (
    <div className="group-settings">
      <HeaderItem />
      <h2>{name}</h2>
      {showMemberCount && (
        <>
          <SpacerLG />
          <div role="button" className="subtle">
            {window.i18n('members', subscriberCount)}
          </div>
          <SpacerLG />
        </>
      )}
      {showUpdateGroupNameButton && (
        <div
          className="group-settings-item"
          role="button"
          onClick={async () => {
            await showUpdateGroupNameByConvoId(id);
          }}
        >
          {isPublic ? window.i18n('editGroup') : window.i18n('editGroupName')}
        </div>
      )}
      {showAddRemoveModeratorsButton && (
        <>
          <div
            className="group-settings-item"
            role="button"
            onClick={() => {
              showAddModeratorsByConvoId(id);
            }}
          >
            {window.i18n('addModerators')}
          </div>
          <div
            className="group-settings-item"
            role="button"
            onClick={() => {
              showRemoveModeratorsByConvoId(id);
            }}
          >
            {window.i18n('removeModerators')}
          </div>
        </>
      )}

      {showUpdateGroupMembersButton && (
        <div
          className="group-settings-item"
          role="button"
          onClick={async () => {
            await showUpdateGroupMembersByConvoId(id);
          }}
        >
          {window.i18n('groupMembers')}
        </div>
      )}

      {hasDisappearingMessages && (
        <SessionDropdown
          label={window.i18n('disappearingMessages')}
          options={disappearingMessagesOptions}
        />
      )}

      <MediaGallery documents={documents} media={media} />
      {isGroup && (
        // tslint:disable-next-line: use-simple-attributes
        <SessionButton
          text={leaveGroupString}
          buttonColor={SessionButtonColor.Danger}
          disabled={isKickedFromGroup || left}
          buttonType={SessionButtonType.SquareOutline}
          onClick={deleteConvoAction}
        />
      )}
    </div>
  );
};