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

import * as React from 'react';

import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';

import { EmojiPicker } from '../emoji/EmojiPicker';
import { setupI18n } from '../../util/setupI18n';
import enMessages from '../../../_locales/en/messages.json';
import type { PropsType as TimelineItemProps } from './TimelineItem';
import { TimelineItem } from './TimelineItem';
import { UniversalTimerNotification } from './UniversalTimerNotification';
import { CallMode } from '../../types/Calling';
import { AvatarColors } from '../../types/Colors';
import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation';
import { WidthBreakpoint } from '../_util';
import { ThemeType } from '../../types/Util';

const i18n = setupI18n('en', enMessages);

const renderEmojiPicker: TimelineItemProps['renderEmojiPicker'] = ({
  onClose,
  onPickEmoji,
  ref,
}) => (
  <EmojiPicker
    i18n={setupI18n('en', enMessages)}
    skinTone={0}
    onSetSkinTone={action('EmojiPicker::onSetSkinTone')}
    ref={ref}
    onClose={onClose}
    onPickEmoji={onPickEmoji}
  />
);

const renderReactionPicker: TimelineItemProps['renderReactionPicker'] = () => (
  <div />
);

const renderContact = (conversationId: string) => (
  <React.Fragment key={conversationId}>{conversationId}</React.Fragment>
);

const renderUniversalTimerNotification = () => (
  <UniversalTimerNotification i18n={i18n} expireTimer={3600} />
);

const getDefaultProps = () => ({
  containerElementRef: React.createRef<HTMLElement>(),
  containerWidthBreakpoint: WidthBreakpoint.Wide,
  conversationId: 'conversation-id',
  getPreferredBadge: () => undefined,
  id: 'asdf',
  isSelected: false,
  interactionMode: 'keyboard' as const,
  theme: ThemeType.light,
  selectMessage: action('selectMessage'),
  reactToMessage: action('reactToMessage'),
  checkForAccount: action('checkForAccount'),
  clearSelectedMessage: action('clearSelectedMessage'),
  contactSupport: action('contactSupport'),
  replyToMessage: action('replyToMessage'),
  retrySend: action('retrySend'),
  deleteMessage: action('deleteMessage'),
  deleteMessageForEveryone: action('deleteMessageForEveryone'),
  kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
  learnMoreAboutDeliveryIssue: action('learnMoreAboutDeliveryIssue'),
  markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
  markViewed: action('markViewed'),
  messageExpanded: action('messageExpanded'),
  showMessageDetail: action('showMessageDetail'),
  openConversation: action('openConversation'),
  showContactDetail: action('showContactDetail'),
  showContactModal: action('showContactModal'),
  showForwardMessageModal: action('showForwardMessageModal'),
  showVisualAttachment: action('showVisualAttachment'),
  downloadAttachment: action('downloadAttachment'),
  displayTapToViewMessage: action('displayTapToViewMessage'),
  doubleCheckMissingQuoteReference: action('doubleCheckMissingQuoteReference'),
  showExpiredIncomingTapToViewToast: action(
    'showExpiredIncomingTapToViewToast'
  ),
  showExpiredOutgoingTapToViewToast: action(
    'showExpiredIncomingTapToViewToast'
  ),
  onHeightChange: action('onHeightChange'),
  openLink: action('openLink'),
  scrollToQuotedMessage: action('scrollToQuotedMessage'),
  downloadNewVersion: action('downloadNewVersion'),
  showIdentity: action('showIdentity'),
  messageSizeChanged: action('messageSizeChanged'),
  startCallingLobby: action('startCallingLobby'),
  returnToActiveCall: action('returnToActiveCall'),
  previousItem: undefined,
  nextItem: undefined,

  renderContact,
  renderUniversalTimerNotification,
  renderEmojiPicker,
  renderReactionPicker,
  renderAudioAttachment: () => <div>*AudioAttachment*</div>,
});

storiesOf('Components/Conversation/TimelineItem', module)
  .add('Plain Message', () => {
    const item = {
      type: 'message',
      data: {
        id: 'id-1',
        direction: 'incoming',
        timestamp: Date.now(),
        author: {
          phoneNumber: '(202) 555-2001',
          color: AvatarColors[0],
        },
        text: '🔥',
      },
    } as TimelineItemProps['item'];

    return <TimelineItem {...getDefaultProps()} item={item} i18n={i18n} />;
  })
  .add('Notification', () => {
    const items = [
      {
        type: 'timerNotification',
        data: {
          phoneNumber: '(202) 555-0000',
          expireTimer: 60,
          ...getDefaultConversation(),
          type: 'fromOther',
        },
      },
      {
        type: 'universalTimerNotification',
        data: null,
      },
      {
        type: 'chatSessionRefreshed',
      },
      {
        type: 'safetyNumberNotification',
        data: {
          isGroup: false,
          contact: getDefaultConversation(),
        },
      },
      {
        type: 'deliveryIssue',
        data: {
          sender: getDefaultConversation(),
        },
      },
      {
        type: 'changeNumberNotification',
        data: {
          sender: getDefaultConversation(),
          timestamp: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // declined incoming audio
          callMode: CallMode.Direct,
          wasDeclined: true,
          wasIncoming: true,
          wasVideoCall: false,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // declined incoming video
          callMode: CallMode.Direct,
          wasDeclined: true,
          wasIncoming: true,
          wasVideoCall: true,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // accepted incoming audio
          callMode: CallMode.Direct,
          acceptedTime: Date.now() - 300,
          wasDeclined: false,
          wasIncoming: true,
          wasVideoCall: false,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // accepted incoming video
          callMode: CallMode.Direct,
          acceptedTime: Date.now() - 400,
          wasDeclined: false,
          wasIncoming: true,
          wasVideoCall: true,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // missed (neither accepted nor declined) incoming audio
          callMode: CallMode.Direct,
          wasDeclined: false,
          wasIncoming: true,
          wasVideoCall: false,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // missed (neither accepted nor declined) incoming video
          callMode: CallMode.Direct,
          wasDeclined: false,
          wasIncoming: true,
          wasVideoCall: true,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // accepted outgoing audio
          callMode: CallMode.Direct,
          acceptedTime: Date.now() - 200,
          wasDeclined: false,
          wasIncoming: false,
          wasVideoCall: false,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // accepted outgoing video
          callMode: CallMode.Direct,
          acceptedTime: Date.now() - 200,
          wasDeclined: false,
          wasIncoming: false,
          wasVideoCall: true,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // declined outgoing audio
          callMode: CallMode.Direct,
          wasDeclined: true,
          wasIncoming: false,
          wasVideoCall: false,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // declined outgoing video
          callMode: CallMode.Direct,
          wasDeclined: true,
          wasIncoming: false,
          wasVideoCall: true,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // unanswered (neither accepted nor declined) outgoing audio
          callMode: CallMode.Direct,
          wasDeclined: false,
          wasIncoming: false,
          wasVideoCall: false,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // unanswered (neither accepted nor declined) outgoing video
          callMode: CallMode.Direct,
          wasDeclined: false,
          wasIncoming: false,
          wasVideoCall: true,
          endedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // ongoing group call
          callMode: CallMode.Group,
          conversationId: 'abc123',
          creator: {
            firstName: 'Luigi',
            isMe: false,
            title: 'Luigi Mario',
          },
          ended: false,
          deviceCount: 1,
          maxDevices: 16,
          startedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // ongoing group call started by you
          callMode: CallMode.Group,
          conversationId: 'abc123',
          creator: {
            firstName: 'Peach',
            isMe: true,
            title: 'Princess Peach',
          },
          ended: false,
          deviceCount: 1,
          maxDevices: 16,
          startedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // ongoing group call, creator unknown
          callMode: CallMode.Group,
          conversationId: 'abc123',
          ended: false,
          deviceCount: 1,
          maxDevices: 16,
          startedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // ongoing and active group call
          callMode: CallMode.Group,
          activeCallConversationId: 'abc123',
          conversationId: 'abc123',
          creator: {
            firstName: 'Luigi',
            isMe: false,
            title: 'Luigi Mario',
          },
          ended: false,
          deviceCount: 1,
          maxDevices: 16,
          startedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // ongoing group call, but you're in another one
          callMode: CallMode.Group,
          activeCallConversationId: 'abc123',
          conversationId: 'xyz987',
          creator: {
            firstName: 'Luigi',
            isMe: false,
            title: 'Luigi Mario',
          },
          ended: false,
          deviceCount: 1,
          maxDevices: 16,
          startedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // ongoing full group call
          callMode: CallMode.Group,
          conversationId: 'abc123',
          creator: {
            firstName: 'Luigi',
            isMe: false,
            title: 'Luigi Mario',
          },
          ended: false,
          deviceCount: 16,
          maxDevices: 16,
          startedTime: Date.now(),
        },
      },
      {
        type: 'callHistory',
        data: {
          // finished call
          callMode: CallMode.Group,
          conversationId: 'abc123',
          creator: {
            firstName: 'Luigi',
            isMe: false,
            title: 'Luigi Mario',
          },
          ended: true,
          deviceCount: 0,
          maxDevices: 16,
          startedTime: Date.now(),
        },
      },
      {
        type: 'linkNotification',
        data: null,
      },
      {
        type: 'profileChange',
        data: {
          change: {
            type: 'name',
            oldName: 'Fred',
            newName: 'John',
          },
          changedContact: getDefaultConversation(),
        },
      },
      {
        type: 'resetSessionNotification',
        data: null,
      },
      {
        type: 'unsupportedMessage',
        data: {
          canProcessNow: true,
          contact: getDefaultConversation(),
        },
      },
      {
        type: 'unsupportedMessage',
        data: {
          canProcessNow: false,
          contact: getDefaultConversation(),
        },
      },
      {
        type: 'verificationNotification',
        data: {
          type: 'markVerified',
          isLocal: false,
          contact: getDefaultConversation(),
        },
      },
      {
        type: 'verificationNotification',
        data: {
          type: 'markVerified',
          isLocal: true,
          contact: getDefaultConversation(),
        },
      },
      {
        type: 'verificationNotification',
        data: {
          type: 'markNotVerified',
          isLocal: false,
          contact: getDefaultConversation(),
        },
      },
      {
        type: 'verificationNotification',
        data: {
          type: 'markNotVerified',
          isLocal: true,
          contact: getDefaultConversation(),
        },
      },
    ];

    return (
      <>
        {items.map((item, index) => (
          <React.Fragment key={index}>
            <TimelineItem
              {...getDefaultProps()}
              item={item as TimelineItemProps['item']}
              i18n={i18n}
            />
          </React.Fragment>
        ))}
      </>
    );
  })
  .add('Unknown Type', () => {
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore: intentional
    const item = {
      type: 'random',
      data: {
        somethin: 'somethin',
      },
    } as TimelineItemProps['item'];

    return <TimelineItem {...getDefaultProps()} item={item} i18n={i18n} />;
  })
  .add('Missing Item', () => {
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore: intentional
    const item = null as TimelineItemProps['item'];

    return <TimelineItem {...getDefaultProps()} item={item} i18n={i18n} />;
  });
