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

import * as React from 'react';
import PQueue from 'p-queue';
import type { SortEndHandler } from 'react-sortable-hoc';
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
import * as styles from './StickerGrid.scss';
import type { Props as StickerFrameProps } from './StickerFrame';
import { StickerFrame } from './StickerFrame';
import { stickersDuck } from '../store';
import type { Props as DropZoneProps } from '../elements/DropZone';
import { DropZone } from '../elements/DropZone';
import { processStickerImage } from '../util/preload';
import { useI18n } from '../util/i18n';

const queue = new PQueue({ concurrency: 3, timeout: 1000 * 60 * 2 });

const SmartStickerFrame = SortableElement(
  ({ id, showGuide, mode }: StickerFrameProps) => {
    const data = stickersDuck.useStickerData(id);
    const actions = stickersDuck.useStickerActions();
    const image = data.imageData ? data.imageData.src : undefined;

    return (
      <StickerFrame
        id={id}
        showGuide={showGuide}
        mode={mode}
        image={image}
        onRemove={actions.removeSticker}
        onPickEmoji={actions.setEmoji}
        emojiData={data.emoji}
      />
    );
  }
);

export type Props = Pick<StickerFrameProps, 'showGuide' | 'mode'>;

export type InnerGridProps = Props & {
  ids: Array<string>;
};

const InnerGrid = SortableContainer(
  ({ ids, mode, showGuide }: InnerGridProps) => {
    const i18n = useI18n();
    const containerClassName = ids.length > 0 ? styles.grid : styles.drop;
    const frameMode = mode === 'add' ? 'removable' : 'pick-emoji';

    const actions = stickersDuck.useStickerActions();

    const handleDrop = React.useCallback<DropZoneProps['onDrop']>(
      async paths => {
        actions.initializeStickers(paths);
        paths.forEach(path => {
          queue.add(async () => {
            try {
              const stickerImage = await processStickerImage(path);
              actions.addImageData(stickerImage);
            } catch (e) {
              window.SignalContext.log.error(
                'Error processing image:',
                e?.stack ? e.stack : String(e)
              );
              actions.removeSticker(path);
              actions.addToast({
                key:
                  (e || {}).errorMessageI18nKey ||
                  'StickerCreator--Toasts--errorProcessing',
              });
            }
          });
        });
      },
      [actions]
    );

    return (
      <div className={containerClassName}>
        {ids.length > 0 ? (
          <>
            {ids.map((p, i) => (
              <SmartStickerFrame
                key={p}
                index={i}
                id={p}
                showGuide={showGuide}
                mode={frameMode}
              />
            ))}
            {mode === 'add' && ids.length < stickersDuck.maxStickers ? (
              <StickerFrame
                showGuide={showGuide}
                mode="add"
                onDrop={handleDrop}
              />
            ) : null}
          </>
        ) : (
          <DropZone
            label={i18n('StickerCreator--DropStage--dragDrop')}
            onDrop={handleDrop}
          />
        )}
      </div>
    );
  }
);

export const StickerGrid = SortableContainer((props: Props) => {
  const ids = stickersDuck.useStickerOrder();
  const actions = stickersDuck.useStickerActions();
  const handleSortEnd = React.useCallback<SortEndHandler>(
    sortEnd => {
      actions.moveSticker(sortEnd);
    },
    [actions]
  );

  return (
    <InnerGrid
      {...props}
      ids={ids}
      axis="xy"
      onSortEnd={handleSortEnd}
      useDragHandle
    />
  );
});