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

import Fuse from 'fuse.js';
import React, { useEffect, useState } from 'react';
import classNames from 'classnames';

import type {
  ConversationType,
  ShowConversationType,
} from '../state/ducks/conversations';
import type {
  ConversationStoryType,
  MyStoryType,
  StoryViewType,
} from '../types/Stories';
import type { LocalizerType } from '../types/Util';
import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
import type { ShowToastActionCreatorType } from '../state/ducks/toast';
import type { ViewUserStoriesActionCreatorType } from '../state/ducks/stories';
import { ContextMenu } from './ContextMenu';
import { MyStoriesButton } from './MyStoriesButton';
import { SearchInput } from './SearchInput';
import { StoriesAddStoryButton } from './StoriesAddStoryButton';
import { StoryListItem } from './StoryListItem';
import { Theme } from '../util/theme';
import { isNotNil } from '../util/isNotNil';
import { useRestoreFocus } from '../hooks/useRestoreFocus';

const FUSE_OPTIONS: Fuse.IFuseOptions<ConversationStoryType> = {
  getFn: (story, path) => {
    if (path[0] === 'searchNames' || path === 'searchNames') {
      return [story.storyView.sender.title, story.storyView.sender.name].filter(
        isNotNil
      );
    }

    return story.group?.title ?? '';
  },
  keys: [
    {
      name: 'searchNames',
      weight: 1,
    },
    {
      name: 'group',
      weight: 1,
    },
  ],
  threshold: 0.1,
};

function search(
  stories: ReadonlyArray<ConversationStoryType>,
  searchTerm: string
): Array<ConversationStoryType> {
  return new Fuse<ConversationStoryType>(stories, FUSE_OPTIONS)
    .search(searchTerm)
    .map(result => result.item);
}

function getNewestMyStory(story: MyStoryType): StoryViewType {
  return story.stories[0];
}

export type PropsType = {
  getPreferredBadge: PreferredBadgeSelectorType;
  hiddenStories: Array<ConversationStoryType>;
  i18n: LocalizerType;
  me: ConversationType;
  myStories: Array<MyStoryType>;
  onAddStory: (file?: File) => unknown;
  onMyStoriesClicked: () => unknown;
  onStoriesSettings: () => unknown;
  queueStoryDownload: (storyId: string) => unknown;
  showConversation: ShowConversationType;
  showToast: ShowToastActionCreatorType;
  stories: Array<ConversationStoryType>;
  toggleHideStories: (conversationId: string) => unknown;
  toggleStoriesView: () => unknown;
  viewUserStories: ViewUserStoriesActionCreatorType;
};

export const StoriesPane = ({
  getPreferredBadge,
  hiddenStories,
  i18n,
  me,
  myStories,
  onAddStory,
  onMyStoriesClicked,
  onStoriesSettings,
  queueStoryDownload,
  showConversation,
  showToast,
  stories,
  toggleHideStories,
  toggleStoriesView,
  viewUserStories,
}: PropsType): JSX.Element => {
  const [searchTerm, setSearchTerm] = useState('');
  const [isShowingHiddenStories, setIsShowingHiddenStories] = useState(false);
  const [renderedStories, setRenderedStories] =
    useState<Array<ConversationStoryType>>(stories);

  useEffect(() => {
    if (searchTerm) {
      setRenderedStories(search(stories, searchTerm));
    } else {
      setRenderedStories(stories);
    }
  }, [searchTerm, stories]);

  const [focusRef] = useRestoreFocus();

  return (
    <>
      <div className="Stories__pane__header">
        <button
          ref={focusRef}
          aria-label={i18n('back')}
          className="Stories__pane__header--back"
          onClick={toggleStoriesView}
          tabIndex={0}
          type="button"
        />
        <div className="Stories__pane__header--title">
          {i18n('Stories__title')}
        </div>
        <StoriesAddStoryButton
          i18n={i18n}
          moduleClassName="Stories__pane__add-story"
          onAddStory={onAddStory}
          showToast={showToast}
        />
        <ContextMenu
          i18n={i18n}
          menuOptions={[
            {
              label: i18n('StoriesSettings__context-menu'),
              onClick: () => onStoriesSettings(),
            },
          ]}
          moduleClassName="Stories__pane__settings"
          popperOptions={{
            placement: 'bottom',
            strategy: 'absolute',
          }}
          theme={Theme.Dark}
        />
      </div>
      <SearchInput
        i18n={i18n}
        moduleClassName="Stories__search"
        onChange={event => {
          setSearchTerm(event.target.value);
        }}
        placeholder={i18n('search')}
        value={searchTerm}
      />
      <div className="Stories__pane__list">
        <>
          <MyStoriesButton
            hasMultiple={
              myStories.length ? myStories[0].stories.length > 1 : false
            }
            i18n={i18n}
            me={me}
            newestStory={
              myStories.length ? getNewestMyStory(myStories[0]) : undefined
            }
            onAddStory={onAddStory}
            onClick={onMyStoriesClicked}
            queueStoryDownload={queueStoryDownload}
            showToast={showToast}
          />
          {renderedStories.map(story => (
            <StoryListItem
              conversationId={story.conversationId}
              getPreferredBadge={getPreferredBadge}
              hasReplies={story.hasReplies}
              hasRepliesFromSelf={story.hasRepliesFromSelf}
              group={story.group}
              i18n={i18n}
              key={story.storyView.timestamp}
              onGoToConversation={conversationId => {
                showConversation({ conversationId });
                toggleStoriesView();
              }}
              onHideStory={toggleHideStories}
              queueStoryDownload={queueStoryDownload}
              story={story.storyView}
              viewUserStories={viewUserStories}
            />
          ))}
          {Boolean(hiddenStories.length) && (
            <>
              <button
                className={classNames('Stories__hidden-stories', {
                  'Stories__hidden-stories--expanded': isShowingHiddenStories,
                })}
                onClick={() =>
                  setIsShowingHiddenStories(!isShowingHiddenStories)
                }
                type="button"
              >
                {i18n('Stories__hidden-stories')}
              </button>
              {isShowingHiddenStories &&
                hiddenStories.map(story => (
                  <StoryListItem
                    conversationId={story.conversationId}
                    getPreferredBadge={getPreferredBadge}
                    group={story.group}
                    i18n={i18n}
                    isHidden
                    key={story.storyView.timestamp}
                    onGoToConversation={conversationId => {
                      showConversation({ conversationId });
                      toggleStoriesView();
                    }}
                    onHideStory={toggleHideStories}
                    queueStoryDownload={queueStoryDownload}
                    story={story.storyView}
                    viewUserStories={viewUserStories}
                  />
                ))}
            </>
          )}
          {!stories.length && (
            <div className="Stories__pane__list--empty">
              {i18n('Stories__list-empty')}
            </div>
          )}
        </>
      </div>
    </>
  );
};