// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import React, { useState, useEffect } from 'react';
import { usePopper } from 'react-popper';
import { isEqual, noop } from 'lodash';

import type { LocalizerType } from '../types/Util';
import { Modal } from './Modal';
import { Button, ButtonVariant } from './Button';
import {
  ReactionPickerPicker,
  ReactionPickerPickerEmojiButton,
  ReactionPickerPickerStyle,
} from './ReactionPickerPicker';
import { EmojiPicker } from './emoji/EmojiPicker';
import { DEFAULT_PREFERRED_REACTION_EMOJI_SHORT_NAMES } from '../reactions/constants';
import { convertShortName } from './emoji/lib';
import { offsetDistanceModifier } from '../util/popperUtil';
import { handleOutsideClick } from '../util/handleOutsideClick';
import type { EmojiSkinTone } from './fun/data/emojis';

export type PropsType = {
  draftPreferredReactions: ReadonlyArray<string>;
  hadSaveError: boolean;
  i18n: LocalizerType;
  isSaving: boolean;
  originalPreferredReactions: ReadonlyArray<string>;
  recentEmojis: ReadonlyArray<string>;
  selectedDraftEmojiIndex: undefined | number;
  emojiSkinToneDefault: EmojiSkinTone;

  cancelCustomizePreferredReactionsModal(): unknown;
  deselectDraftEmoji(): unknown;
  onEmojiSkinToneDefaultChange: (emojiSkinToneDefault: EmojiSkinTone) => void;
  replaceSelectedDraftEmoji(newEmoji: string): unknown;
  resetDraftEmoji(): unknown;
  savePreferredReactions(): unknown;
  selectDraftEmojiToBeReplaced(index: number): unknown;
};

export function CustomizingPreferredReactionsModal({
  cancelCustomizePreferredReactionsModal,
  deselectDraftEmoji,
  draftPreferredReactions,
  emojiSkinToneDefault,
  hadSaveError,
  i18n,
  isSaving,
  onEmojiSkinToneDefaultChange,
  originalPreferredReactions,
  recentEmojis,
  replaceSelectedDraftEmoji,
  resetDraftEmoji,
  savePreferredReactions,
  selectDraftEmojiToBeReplaced,
  selectedDraftEmojiIndex,
}: Readonly<PropsType>): JSX.Element {
  const [referenceElement, setReferenceElement] =
    useState<null | HTMLDivElement>(null);
  const [popperElement, setPopperElement] = useState<null | HTMLDivElement>(
    null
  );
  const emojiPickerPopper = usePopper(referenceElement, popperElement, {
    placement: 'bottom',
    modifiers: [
      offsetDistanceModifier(8),
      {
        name: 'preventOverflow',
        options: { altAxis: true },
      },
    ],
  });

  const isSomethingSelected = selectedDraftEmojiIndex !== undefined;

  useEffect(() => {
    if (!isSomethingSelected) {
      return noop;
    }

    return handleOutsideClick(
      () => {
        deselectDraftEmoji();
        return true;
      },
      {
        containerElements: [popperElement],
        name: 'CustomizingPreferredReactionsModal.draftEmoji',
      }
    );
  }, [isSomethingSelected, popperElement, deselectDraftEmoji]);

  const hasChanged = !isEqual(
    originalPreferredReactions,
    draftPreferredReactions
  );
  const canReset =
    !isSaving &&
    !isEqual(
      DEFAULT_PREFERRED_REACTION_EMOJI_SHORT_NAMES.map(shortName =>
        convertShortName(shortName, emojiSkinToneDefault)
      ),
      draftPreferredReactions
    );
  const canSave = !isSaving && hasChanged;

  const footer = (
    <>
      <Button
        disabled={!canReset}
        onClick={() => {
          resetDraftEmoji();
        }}
        onKeyDown={event => {
          if (event.key === 'Enter' || event.key === 'Space') {
            resetDraftEmoji();
          }
        }}
        variant={ButtonVariant.SecondaryAffirmative}
      >
        {i18n('icu:reset')}
      </Button>
      <Button
        disabled={!canSave}
        onClick={() => {
          savePreferredReactions();
        }}
        onKeyDown={event => {
          if (event.key === 'Enter' || event.key === 'Space') {
            savePreferredReactions();
          }
        }}
      >
        {i18n('icu:save')}
      </Button>
    </>
  );

  return (
    <Modal
      modalName="CustomizingPreferredReactionsModal"
      moduleClassName="module-CustomizingPreferredReactionsModal"
      hasXButton
      i18n={i18n}
      onClose={() => {
        cancelCustomizePreferredReactionsModal();
      }}
      title={i18n('icu:CustomizingPreferredReactions__title')}
      modalFooter={footer}
    >
      <div className="module-CustomizingPreferredReactionsModal__small-emoji-picker-wrapper">
        <ReactionPickerPicker
          isSomethingSelected={isSomethingSelected}
          pickerStyle={ReactionPickerPickerStyle.Menu}
          ref={setReferenceElement}
        >
          {draftPreferredReactions.map((emoji, index) => (
            <ReactionPickerPickerEmojiButton
              emoji={emoji}
              // The index is the only thing that uniquely identifies the emoji, because
              //   there can be duplicates in the list.
              // eslint-disable-next-line react/no-array-index-key
              key={index}
              onClick={() => {
                selectDraftEmojiToBeReplaced(index);
              }}
              isSelected={index === selectedDraftEmojiIndex}
            />
          ))}
        </ReactionPickerPicker>
        {hadSaveError
          ? i18n('icu:CustomizingPreferredReactions__had-save-error')
          : i18n('icu:CustomizingPreferredReactions__subtitle')}
      </div>
      {isSomethingSelected && (
        <div
          ref={setPopperElement}
          style={emojiPickerPopper.styles.popper}
          {...emojiPickerPopper.attributes.popper}
        >
          <EmojiPicker
            i18n={i18n}
            onPickEmoji={pickedEmoji => {
              const emoji = convertShortName(
                pickedEmoji.shortName,
                pickedEmoji.skinTone
              );
              replaceSelectedDraftEmoji(emoji);
            }}
            recentEmojis={recentEmojis}
            emojiSkinToneDefault={emojiSkinToneDefault}
            onEmojiSkinToneDefaultChange={onEmojiSkinToneDefaultChange}
            onClose={() => {
              deselectDraftEmoji();
            }}
            wasInvokedFromKeyboard={false}
          />
        </div>
      )}
    </Modal>
  );
}
