import React from 'react';
import { Item, Submenu } from 'react-contexify';
import { useDispatch, useSelector } from 'react-redux';
import {
  useAvatarPath,
  useConversationUsername,
  useHasNickname,
  useIsActive,
  useIsBlinded,
  useIsBlocked,
  useIsGroupV2,
  useIsIncomingRequest,
  useIsKickedFromGroup,
  useIsMe,
  useIsPrivate,
  useIsPrivateAndFriend,
  useIsPublic,
  useLastMessage,
  useNotificationSetting,
  useWeAreAdmin,
} from '../../hooks/useParamSelector';
import {
  ConversationInteractionStatus,
  ConversationInteractionType,
  approveConvoAndSendResponse,
  blockConvoById,
  clearNickNameByConvoId,
  copyPublicKeyByConvoId,
  declineConversationWithConfirm,
  deleteAllMessagesByConvoIdWithConfirmation,
  markAllReadByConvoId,
  setNotificationForConvoId,
  showAddModeratorsByConvoId,
  showBanUserByConvoId,
  showInviteContactByConvoId,
  showLeaveGroupByConvoId,
  showLeavePrivateConversationbyConvoId,
  showRemoveModeratorsByConvoId,
  showUnbanUserByConvoId,
  showUpdateGroupNameByConvoId,
  unblockConvoById,
} from '../../interactions/conversationInteractions';
import {
  ConversationNotificationSetting,
  ConversationNotificationSettingType,
} from '../../models/conversationAttributes';
import { ConvoHub } from '../../session/conversations';
import { PubKey } from '../../session/types';
import {
  changeNickNameModal,
  updateConfirmModal,
  updateUserDetailsModal,
} from '../../state/ducks/modalDialog';
import { useConversationIdOrigin } from '../../state/selectors/conversations';
import { getIsMessageSection } from '../../state/selectors/section';
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
import { LocalizerKeys } from '../../types/LocalizerKeys';
import { SessionButtonColor } from '../basic/SessionButton';
import { useConvoIdFromContext } from '../leftpane/conversation-list-item/ConvoIdContext';
/** Menu items standardized */
export const InviteContactMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isPublic = useIsPublic(convoId);
  if (isPublic) {
    return (
      -  {
          showInviteContactByConvoId(convoId);
        }}
      >
        {window.i18n('inviteContacts')}
      );
  }
  return null;
};
export const MarkConversationUnreadMenuItem = (): JSX.Element | null => {
  const conversationId = useConvoIdFromContext();
  const isMessagesSection = useSelector(getIsMessageSection);
  const isPrivate = useIsPrivate(conversationId);
  const isPrivateAndFriend = useIsPrivateAndFriend(conversationId);
  if (isMessagesSection && (!isPrivate || (isPrivate && isPrivateAndFriend))) {
    const conversation = ConvoHub.use().get(conversationId);
    const markUnread = () => {
      void conversation?.markAsUnread(true);
    };
    return
- {window.i18n('markUnread')};
  }
  return null;
};
/**
 * This menu item can be used to completely remove a contact and reset the flags of that conversation.
 * i.e. after confirmation is made, this contact will be removed from the ContactWrapper, and its blocked and approved state reset.
 * Note: We keep the entry in the database as the user profile might still be needed for communities/groups where this user.
 */
export const DeletePrivateContactMenuItem = () => {
  const dispatch = useDispatch();
  const convoId = useConvoIdFromContext();
  const isPrivate = useIsPrivate(convoId);
  const isRequest = useIsIncomingRequest(convoId);
  if (isPrivate && !isRequest) {
    const menuItemText = window.i18n('editMenuDeleteContact');
    const onClickClose = () => {
      dispatch(updateConfirmModal(null));
    };
    const showConfirmationModal = () => {
      dispatch(
        updateConfirmModal({
          title: menuItemText,
          message: window.i18n('deleteContactConfirmation'),
          onClickClose,
          okTheme: SessionButtonColor.Danger,
          onClickOk: async () => {
            await ConvoHub.use().delete1o1(convoId, {
              fromSyncMessage: false,
              justHidePrivate: false,
              keepMessages: false,
            });
          },
        })
      );
    };
    return
- {menuItemText};
  }
  return null;
};
export const LeaveGroupOrCommunityMenuItem = () => {
  const convoId = useConvoIdFromContext();
  const username = useConversationUsername(convoId) || convoId;
  const isKickedFromGroup = useIsKickedFromGroup(convoId);
  const isPrivate = useIsPrivate(convoId);
  const isPublic = useIsPublic(convoId);
  const lastMessage = useLastMessage(convoId);
  if (!isKickedFromGroup && !isPrivate) {
    return (
-  {
          void showLeaveGroupByConvoId(convoId, username);
        }}
      >
        {isPublic
          ? window.i18n('leaveCommunity')
          : lastMessage?.interactionType === ConversationInteractionType.Leave &&
              lastMessage?.interactionStatus === ConversationInteractionStatus.Error
            ? window.i18n('deleteConversation')
            : window.i18n('leaveGroup')}
      );
  }
  return null;
};
export const ShowUserDetailsMenuItem = () => {
  const dispatch = useDispatch();
  const convoId = useConvoIdFromContext();
  const isPrivate = useIsPrivate(convoId);
  const avatarPath = useAvatarPath(convoId);
  const userName = useConversationUsername(convoId) || convoId;
  const isBlinded = useIsBlinded(convoId);
  if (isPrivate && !isBlinded) {
    return (
-  {
          dispatch(
            updateUserDetailsModal({
              conversationId: convoId,
              userName,
              authorAvatarPath: avatarPath,
            })
          );
        }}
      >
        {window.i18n('showUserDetails')}
      );
  }
  return null;
};
export const UpdateGroupNameMenuItem = () => {
  const convoId = useConvoIdFromContext();
  const isKickedFromGroup = useIsKickedFromGroup(convoId);
  const weAreAdmin = useWeAreAdmin(convoId);
  if (!isKickedFromGroup && weAreAdmin) {
    return (
-  {
          void showUpdateGroupNameByConvoId(convoId);
        }}
      >
        {window.i18n('editGroup')}
      );
  }
  return null;
};
export const RemoveModeratorsMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isPublic = useIsPublic(convoId);
  const isKickedFromGroup = useIsKickedFromGroup(convoId);
  const weAreAdmin = useWeAreAdmin(convoId);
  if (!isKickedFromGroup && weAreAdmin && isPublic) {
    return (
-  {
          showRemoveModeratorsByConvoId(convoId);
        }}
      >
        {window.i18n('removeModerators')}
      );
  }
  return null;
};
export const AddModeratorsMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isPublic = useIsPublic(convoId);
  const isKickedFromGroup = useIsKickedFromGroup(convoId);
  const weAreAdmin = useWeAreAdmin(convoId);
  if (!isKickedFromGroup && weAreAdmin && isPublic) {
    return (
-  {
          showAddModeratorsByConvoId(convoId);
        }}
      >
        {window.i18n('addModerators')}
      );
  }
  return null;
};
export const UnbanMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isPublic = useIsPublic(convoId);
  const isKickedFromGroup = useIsKickedFromGroup(convoId);
  const weAreAdmin = useWeAreAdmin(convoId);
  if (isPublic && !isKickedFromGroup && weAreAdmin) {
    return (
-  {
          showUnbanUserByConvoId(convoId);
        }}
      >
        {window.i18n('unbanUser')}
      );
  }
  return null;
};
export const BanMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isPublic = useIsPublic(convoId);
  const isKickedFromGroup = useIsKickedFromGroup(convoId);
  const weAreAdmin = useWeAreAdmin(convoId);
  if (isPublic && !isKickedFromGroup && weAreAdmin) {
    return (
-  {
          showBanUserByConvoId(convoId);
        }}
      >
        {window.i18n('banUser')}
      );
  }
  return null;
};
export const CopyMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isPublic = useIsPublic(convoId);
  const isPrivate = useIsPrivate(convoId);
  const isBlinded = useIsBlinded(convoId);
  // we want to show the copyId for open groups and private chats only
  if ((isPrivate && !isBlinded) || isPublic) {
    const copyIdLabel = isPublic ? window.i18n('copyOpenGroupURL') : window.i18n('copySessionID');
    return (
-  {
          void copyPublicKeyByConvoId(convoId);
        }}
      >
        {copyIdLabel}
      );
  }
  return null;
};
export const MarkAllReadMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isIncomingRequest = useIsIncomingRequest(convoId);
  if (!isIncomingRequest && !PubKey.isBlinded(convoId)) {
    return (
      // eslint-disable-next-line @typescript-eslint/no-misused-promises
-  markAllReadByConvoId(convoId)}>
        {window.i18n('markAllAsRead')}
      );
  }
  return null;
};
export const BlockMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isMe = useIsMe(convoId);
  const isBlocked = useIsBlocked(convoId);
  const isPrivate = useIsPrivate(convoId);
  const isIncomingRequest = useIsIncomingRequest(convoId);
  if (!isMe && isPrivate && !isIncomingRequest && !PubKey.isBlinded(convoId)) {
    const blockTitle = isBlocked ? window.i18n('unblock') : window.i18n('block');
    const blockHandler = isBlocked
      ? async () => unblockConvoById(convoId)
      : async () => blockConvoById(convoId);
    // eslint-disable-next-line @typescript-eslint/no-misused-promises
    return
- {blockTitle};
  }
  return null;
};
export const ClearNicknameMenuItem = (): JSX.Element | null => {
  const convoId = useConvoIdFromContext();
  const isMe = useIsMe(convoId);
  const hasNickname = useHasNickname(convoId);
  const isPrivate = useIsPrivate(convoId);
  const isPrivateAndFriend = useIsPrivateAndFriend(convoId);
  if (isMe || !hasNickname || !isPrivate || !isPrivateAndFriend) {
    return null;
  }
  return (
    // eslint-disable-next-line @typescript-eslint/no-misused-promises
-  clearNickNameByConvoId(convoId)}>
      {window.i18n('clearNickname')}
    );
};
export const ChangeNicknameMenuItem = () => {
  const convoId = useConvoIdFromContext();
  const isMe = useIsMe(convoId);
  const isPrivate = useIsPrivate(convoId);
  const isPrivateAndFriend = useIsPrivateAndFriend(convoId);
  const dispatch = useDispatch();
  if (isMe || !isPrivate || !isPrivateAndFriend) {
    return null;
  }
  return (
-  {
        dispatch(changeNickNameModal({ conversationId: convoId }));
      }}
    >
      {window.i18n('changeNickname')}
    );
};
/**
 * This menu is always available and can be used to clear the messages in the local database only.
 * No messages are sent, no update are made in the wrappers.
 * Note: Will ask for confirmation before processing.
 */
export const DeleteMessagesMenuItem = () => {
  const convoId = useConvoIdFromContext();
  if (!convoId) {
    return null;
  }
  return (
-  {
        deleteAllMessagesByConvoIdWithConfirmation(convoId);
      }}
    >
      {window.i18n('deleteMessages')}
    );
};
/**
 * This menu item can be used to delete a private conversation after confirmation.
 * It does not reset the flags of that conversation, but just removes the messages locally and hide it from the left pane list.
 * Note: A dialog is opened to ask for confirmation before processing.
 */
export const DeletePrivateConversationMenuItem = () => {
  const convoId = useConvoIdFromContext();
  const username = useConversationUsername(convoId) || convoId;
  const isRequest = useIsIncomingRequest(convoId);
  const isPrivate = useIsPrivate(convoId);
  const isMe = useIsMe(convoId);
  if (!convoId || !isPrivate || isRequest) {
    return null;
  }
  return (
-  {
        showLeavePrivateConversationbyConvoId(convoId, username);
      }}
    >
      {isMe ? window.i18n('hideConversation') : window.i18n('deleteConversation')}
    );
};
export const AcceptMsgRequestMenuItem = () => {
  const convoId = useConvoIdFromContext();
  const isRequest = useIsIncomingRequest(convoId);
  const convo = ConvoHub.use().get(convoId);
  const isPrivate = useIsPrivate(convoId);
  if (isRequest && isPrivate) {
    return (
-  {
          await convo.setDidApproveMe(true);
          await convo.addOutgoingApprovalMessage(Date.now());
          await approveConvoAndSendResponse(convoId);
        }}
      >
        {window.i18n('accept')}
      );
  }
  return null;
};
export const DeclineMsgRequestMenuItem = () => {
  const convoId = useConvoIdFromContext();
  const isRequest = useIsIncomingRequest(convoId);
  const isPrivate = useIsPrivate(convoId);
  const selected = useSelectedConversationKey();
  const isGroupV2 = useIsGroupV2(convoId);
  if ((isPrivate || isGroupV2) && isRequest) {
    return (
-  {
          declineConversationWithConfirm({
            conversationId: convoId,
            syncToDevices: true,
            alsoBlock: false,
            currentlySelectedConvo: selected || undefined,
            conversationIdOrigin: null,
          });
        }}
      >
        {window.i18n('delete')}
      );
  }
  return null;
};
export const DeclineAndBlockMsgRequestMenuItem = () => {
  const convoId = useConvoIdFromContext();
  const isRequest = useIsIncomingRequest(convoId);
  const selected = useSelectedConversationKey();
  const isPrivate = useIsPrivate(convoId);
  const isGroupV2 = useIsGroupV2(convoId);
  const convoOrigin = useConversationIdOrigin(convoId);
  if (isRequest && (isPrivate || (isGroupV2 && convoOrigin))) {
    // to block the author of a groupv2 invitge we need the convoOrigin set
    return (
-  {
          declineConversationWithConfirm({
            conversationId: convoId,
            syncToDevices: true,
            alsoBlock: true,
            currentlySelectedConvo: selected || undefined,
            conversationIdOrigin: convoOrigin ?? null,
          });
        }}
      >
        {window.i18n('block')}
      );
  }
  return null;
};
export const NotificationForConvoMenuItem = (): JSX.Element | null => {
  // Note: this item is used in the header and in the list item, so we need to grab the details
  // from the convoId from the context itself, not the redux selected state
  const convoId = useConvoIdFromContext();
  const currentNotificationSetting = useNotificationSetting(convoId);
  const isBlocked = useIsBlocked(convoId);
  const isActive = useIsActive(convoId);
  const isKickedFromGroup = useIsKickedFromGroup(convoId);
  const isFriend = useIsPrivateAndFriend(convoId);
  const isPrivate = useIsPrivate(convoId);
  if (!convoId || isKickedFromGroup || isBlocked || !isActive || (isPrivate && !isFriend)) {
    return null;
  }
  // const isRtlMode = isRtlBody();
  // exclude mentions_only settings for private chats as this does not make much sense
  const notificationForConvoOptions = ConversationNotificationSetting.filter(n =>
    isPrivate ? n !== 'mentions_only' : true
  ).map((n: ConversationNotificationSettingType) => {
    // do this separately so typescript's compiler likes it
    const keyToUse: LocalizerKeys =
      n === 'all' || !n
        ? 'notificationForConvo_all'
        : n === 'disabled'
          ? 'notificationForConvo_disabled'
          : 'notificationForConvo_mentions_only';
    return { value: n, name: window.i18n(keyToUse) };
  });
  return (
    // Remove the && false to make context menu work with RTL support
    
      {(notificationForConvoOptions || []).map(item => {
        const disabled = item.value === currentNotificationSetting;
        return (
-  {
              void setNotificationForConvoId(convoId, item.value);
            }}
            disabled={disabled}
          >
            {item.name}
          );
      })}
    
  );
  return null;
};