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

import { memo, useState, useEffect, useCallback } from 'react';
import type { LocalizerType } from '../../types/Util.std.ts';
import type { StickerPackType } from '../../state/ducks/stickers.preload.ts';
import type { ShowToastAction } from '../../state/ducks/toast.preload.ts';
import { UserText } from '../UserText.dom.tsx';
import { AxoConfirmDialog } from '../../axo/AxoConfirmDialog.dom.tsx';
import { AxoDialog } from '../../axo/AxoDialog.dom.tsx';
import { tw } from '../../axo/tw.dom.tsx';
import { AxoStackedButton } from '../../axo/AxoStackedButton.dom.tsx';
import { SpinnerV2 } from '../SpinnerV2.dom.tsx';
import { OfficialChatInlineBadge } from '../conversation/OfficialChatInlineBadge.dom.tsx';
import { artAddStickersRoute } from '../../util/signalRoutes.std.ts';
import { drop } from '../../util/drop.std.ts';
import { ToastType } from '../../types/Toast.dom.tsx';
import { fromBase64PackKeyToHex } from '../../util/Stickers.std.ts';
import { useRestoreFocus } from '../../hooks/useRestoreFocus.dom.ts';

export type Props = Readonly<{
  onClose?: () => void;
  closeStickerPackPreview: () => void;
  downloadStickerPack: (
    packId: string,
    packKey: string,
    options: { finalStatus?: 'installed' | 'downloaded'; actionSource: 'ui' }
  ) => void;
  installStickerPack: (
    packId: string,
    packKey: string,
    options: { actionSource: 'ui' }
  ) => void;
  uninstallStickerPack: (
    packId: string,
    packKey: string,
    options: { actionSource: 'ui' }
  ) => void;
  showToast: ShowToastAction;
  pack?: StickerPackType;
  i18n: LocalizerType;
}>;

function renderBody({
  pack,
  i18n,
  handleCopyLink,
  handleStartUninstall,
}: Pick<Props, 'i18n' | 'pack'> & {
  handleCopyLink: () => void;
  handleStartUninstall: () => void;
}) {
  if (pack == null) {
    return null;
  }

  if (pack.status === 'error') {
    return (
      <div className={tw('px-12 py-6 text-center text-destructive')}>
        {i18n('icu:stickers--StickerPreview--Error')}
      </div>
    );
  }

  if (pack.stickerCount === 0) {
    return (
      <div className={tw('flex justify-center py-6')}>
        <SpinnerV2
          variant="no-background-light"
          size={56}
          strokeWidth={2}
          value="indeterminate"
        />
      </div>
    );
  }

  const placeholders = pack.stickerCount - pack.stickers.length;

  return (
    <div className={tw('justify-items-center')}>
      {pack.cover && (
        <img
          className={tw(
            'mb-4 aspect-square max-h-20 w-full max-w-20 object-contain'
          )}
          src={pack.cover.url}
          alt={pack.title}
        />
      )}
      <h2 className={tw('mb-2 type-title-medium')}>
        <UserText text={pack.title} />
        {pack.isBlessed && (
          <span className={tw('ms-1.5')}>
            <OfficialChatInlineBadge />
          </span>
        )}
      </h2>
      <div
        className={tw(
          'mb-3 justify-items-center type-body-medium text-secondary'
        )}
      >
        <div>{pack.author}</div>
        <div>
          {i18n('icu:stickers--StickerPreview--StickerCount', {
            count: pack.stickerCount,
          })}
        </div>
      </div>
      <AxoStackedButton.Row spacing="md">
        <AxoStackedButton.Root
          symbol="link"
          label={i18n('icu:stickers--StickerPreview--Link')}
          onClick={handleCopyLink}
        />
        {pack.status === 'installed' && (
          <AxoStackedButton.Root
            symbol="minus-circle"
            label={i18n('icu:stickers--StickerPreview--Remove')}
            onClick={handleStartUninstall}
          />
        )}
      </AxoStackedButton.Row>
      <div
        className={tw(
          'mt-4 grid w-max grid-cols-5 items-center justify-center gap-2.5'
        )}
      >
        {pack.stickers.map(({ emoji, id, url }) => (
          <img
            key={id}
            className={tw(
              'aspect-square max-h-18 w-full max-w-18 object-contain'
            )}
            src={url}
            alt={
              emoji ??
              i18n('icu:stickers--StickerPreview--StickerNoEmojiAriaLabel')
            }
          />
        ))}
        {Array.from({ length: placeholders }, (_, index) => {
          return (
            <div
              key={index}
              className={tw(
                'aspect-square max-h-18 w-full max-w-18 rounded-md bg-primary'
              )}
            />
          );
        })}
      </div>
    </div>
  );
}

function isInstallFooterVisible(
  pack: StickerPackType | undefined
): pack is StickerPackType {
  return Boolean(
    pack &&
    pack.status != null &&
    pack.status !== 'error' &&
    pack.status !== 'installed'
  );
}

export const StickerPreviewModal = memo(function StickerPreviewModalInner({
  closeStickerPackPreview,
  downloadStickerPack,
  i18n,
  installStickerPack,
  onClose,
  pack,
  showToast,
  uninstallStickerPack,
}: Props) {
  const [confirmingUninstall, setConfirmingUninstall] = useState(false);

  // Restore focus on teardown
  const [focusRef] = useRestoreFocus();

  useEffect(() => {
    if (pack && pack.status === 'known') {
      downloadStickerPack(pack.id, pack.key, { actionSource: 'ui' });
    }
    if (
      pack &&
      pack.status === 'error' &&
      (pack.attemptedStatus === 'downloaded' ||
        pack.attemptedStatus === 'installed')
    ) {
      downloadStickerPack(pack.id, pack.key, {
        actionSource: 'ui',
        finalStatus: pack.attemptedStatus,
      });
    }
    // We only want to attempt downloads on initial load
    // oxlint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (pack) {
      return;
    }

    // Pack fully uninstalled, don't keep the modal open
    closeStickerPackPreview();
  }, [pack, closeStickerPackPreview]);

  const handleClose = useCallback(() => {
    if (pack) {
      closeStickerPackPreview();
    }
    onClose?.();
  }, [closeStickerPackPreview, onClose, pack]);

  const handleInstall = useCallback(() => {
    if (!pack) {
      return;
    }

    if (pack.status === 'ephemeral') {
      downloadStickerPack(pack.id, pack.key, {
        finalStatus: 'installed',
        actionSource: 'ui',
      });
    } else {
      installStickerPack(pack.id, pack.key, { actionSource: 'ui' });
    }
  }, [downloadStickerPack, installStickerPack, pack]);

  const handleStartUninstall = useCallback(() => {
    setConfirmingUninstall(true);
  }, []);

  const handleUninstall = useCallback(() => {
    if (!pack) {
      return;
    }
    uninstallStickerPack(pack.id, pack.key, { actionSource: 'ui' });
    setConfirmingUninstall(false);
  }, [uninstallStickerPack, setConfirmingUninstall, pack]);

  const handleCopyLink = useCallback(() => {
    if (!pack) {
      return;
    }

    const link = artAddStickersRoute
      .toWebUrl({
        packId: pack.id,
        packKey: fromBase64PackKeyToHex(pack.key),
      })
      .toString();
    drop(window.navigator.clipboard.writeText(link));
    showToast({ toastType: ToastType.CopiedStickerPackLink });
  }, [pack, showToast]);

  return (
    <>
      <AxoDialog.Root open onOpenChange={handleClose}>
        <AxoDialog.Content size="md" escape="cancel-is-noop">
          <AxoDialog.Header>
            <AxoDialog.Title screenReaderOnly>
              {i18n('icu:stickers--StickerPreview--Title')}
            </AxoDialog.Title>
            <AxoDialog.Close />
          </AxoDialog.Header>
          <AxoDialog.Body>
            <div ref={focusRef} />
            {renderBody({ pack, i18n, handleCopyLink, handleStartUninstall })}
          </AxoDialog.Body>
          <AxoDialog.Footer>
            {isInstallFooterVisible(pack) && (
              <AxoDialog.Action
                variant="strong-primary"
                onClick={handleInstall}
                pending={pack.status === 'pending'}
              >
                {i18n('icu:stickers--StickerPreview--Install')}
              </AxoDialog.Action>
            )}
          </AxoDialog.Footer>
        </AxoDialog.Content>
      </AxoDialog.Root>

      <AxoConfirmDialog.Root
        open={confirmingUninstall}
        onOpenChange={setConfirmingUninstall}
        // @ts-expect-error ConfirmationDialog migration: Needs title
        title={null}
        description={i18n('icu:stickers--StickerManager--UninstallWarning')}
      >
        <AxoConfirmDialog.Cancel />
        <AxoConfirmDialog.Action
          variant="strong-destructive"
          onClick={handleUninstall}
        >
          {i18n('icu:stickers--StickerManager--Uninstall')}
        </AxoConfirmDialog.Action>
      </AxoConfirmDialog.Root>
    </>
  );
});
