/**
 * @file Activity Feed V2 adapter - wraps @box/activity-feed compound components.
 *
 * Read data comes from the file activities endpoint (already parsed into BUIE FeedItem types by Feed.js).
 * Write/mutate operations still use the traditional v2 API via ActivitySidebar callbacks.
 * @author Box
 */

import * as React from 'react';
import noop from 'lodash/noop';
import { FormattedMessage, useIntl } from 'react-intl';
import { ActivityFeed, useActivityFeedScroll } from '@box/activity-feed';
import TaskModal from '../TaskModal';
import FeedItemRow from './FeedItemRow';
import { serializeEditorContent } from './helpers';
import { transformFeedItem } from './transformers';
import { TASK_COMPLETION_RULE_ALL, TASK_EDIT_MODE_EDIT, TASK_TYPE_APPROVAL } from '../../../constants';
import commonMessages from '../../common/messages';
import draftJsMentionSelectorMessages from '../../../components/form-elements/draft-js-mention-selector/messages';
import messages from '../messages';
import './ActivityFeedV2.scss';
const ActivityFeedV2 = ({
  activeFeedEntryId,
  approverSelectorContacts = [],
  createTask,
  currentUser,
  feedItems,
  getApproverWithQuery,
  getAvatarUrl,
  getMentionAsync,
  getTaskCollaborators,
  hasTasks = true,
  isDisabled = false,
  onAnnotationCopyLink,
  onAnnotationDelete,
  onAnnotationEdit,
  onAnnotationSelect,
  onAnnotationStatusChange,
  onCommentCopyLink,
  onCommentCreate,
  onCommentDelete,
  onCommentUpdate,
  onReplyCreate,
  onReplyDelete,
  onReplyUpdate,
  onShowOnlyMentionsMeChange,
  onShowResolvedChange,
  onTaskAssignmentUpdate,
  onTaskDelete,
  onTaskUpdate,
  onTaskView,
  onVersionHistoryClick,
  showOnlyMentionsMe: showOnlyMentionsMeProp,
  showResolved: showResolvedProp
}) => {
  const intl = useIntl();
  const scrollHandle = useActivityFeedScroll();
  const currentUserId = currentUser?.id;
  const headerTitle = intl.formatMessage(commonMessages.sidebarActivityTitle);
  const scrolledEntryIdRef = React.useRef(null);
  const hasScrolledToEndRef = React.useRef(false);
  const knownIdsBeforePostRef = React.useRef(null);
  const fetchUsers = React.useCallback(async inputValue => {
    const trimmed = inputValue.trim();
    if (!trimmed || !getMentionAsync) {
      return [];
    }
    try {
      const entries = await getMentionAsync(trimmed);
      return entries.map(c => ({
        email: c.email ?? c.login ?? '',
        id: Number(c.id) || 0,
        name: c.name ?? '',
        value: String(c.id)
      }));
    } catch {
      return [];
    }
  }, [getMentionAsync]);
  const fetchAvatarUrls = React.useCallback(async userContacts => {
    const urls = {};
    if (getAvatarUrl) {
      await Promise.all(userContacts.map(async contact => {
        // Key by contact.value; contact.id may collide when ids don't parse as numbers.
        try {
          const url = await getAvatarUrl(contact.value);
          if (url) {
            urls[contact.value] = url;
          }
        } catch {
          // Individual avatar failure should not block other avatars
        }
      }));
    }
    return urls;
  }, [getAvatarUrl]);
  const userSelectorProps = React.useMemo(() => ({
    allowEmptyQuery: true,
    ariaRoleDescription: intl.formatMessage(messages.mentionUserSelectorRoleDescription),
    fetchAvatarUrls,
    fetchUsers,
    loadingAriaLabel: intl.formatMessage(messages.mentionUserSelectorLoading),
    renderEmpty: value => /*#__PURE__*/React.createElement("div", {
      className: "bcs-NewActivityFeed-mentionEmpty"
    }, /*#__PURE__*/React.createElement(FormattedMessage, value.trim() ? draftJsMentionSelectorMessages.noUsersFound : draftJsMentionSelectorMessages.startMention))
  }), [fetchAvatarUrls, fetchUsers, intl]);

  // collaborationPopoverProps must be defined so MentionComponent can
  // destructure onSubmit/onClose from it without crashing. getAvatarUrl is
  // intentionally omitted: the mentionContext contract is synchronous
  // ((id: string) => string) but BUIE's getAvatarUrl is async, so there is
  // no correct sync adapter without a caching layer. Leave it undefined
  // until the vendor contract supports async resolution.
  const mentionContext = React.useMemo(() => ({
    collaborationPopoverProps: {
      onClose: noop,
      onSubmit: noop
    }
  }), []);
  const [localShowOnlyMentionsMe, setLocalShowOnlyMentionsMe] = React.useState(false);
  const [localShowResolved, setLocalShowResolved] = React.useState(false);
  const showOnlyMentionsMe = showOnlyMentionsMeProp ?? localShowOnlyMentionsMe;
  const showResolved = showResolvedProp ?? localShowResolved;
  const handleShowOnlyMentionsMeChange = checked => {
    if (showOnlyMentionsMeProp === undefined) setLocalShowOnlyMentionsMe(checked);
    onShowOnlyMentionsMeChange?.(checked);
  };
  const handleShowResolvedChange = checked => {
    if (showResolvedProp === undefined) setLocalShowResolved(checked);
    onShowResolvedChange?.(checked);
  };
  const [isTaskFormOpen, setIsTaskFormOpen] = React.useState(false);
  const [taskType, setTaskType] = React.useState(TASK_TYPE_APPROVAL);
  const [taskError, setTaskError] = React.useState(null);
  const [editingTask, setEditingTask] = React.useState(null);
  const [editingAssignees, setEditingAssignees] = React.useState(null);
  const handleTaskModalClose = React.useCallback(() => {
    setIsTaskFormOpen(false);
    setTaskError(null);
    setEditingTask(null);
    setEditingAssignees(null);
  }, []);
  const handleTaskEdit = React.useCallback(async task => {
    let fullAssignees = task.assigned_to;
    if (task.assigned_to?.next_marker && getTaskCollaborators) {
      try {
        fullAssignees = await getTaskCollaborators(task);
      } catch (error) {
        // eslint-disable-next-line no-console
        console.error(`ActivityFeedV2: failed to load assignees for task "${task.id}"`, error);
      }
    }
    setEditingTask(task);
    setEditingAssignees(fullAssignees);
    setTaskType(task.task_type);
    setIsTaskFormOpen(true);
  }, [getTaskCollaborators]);
  const transformedItems = React.useMemo(() => {
    if (!feedItems) return [];
    return feedItems.reduce((acc, item) => {
      const transformed = transformFeedItem(item, currentUserId);
      if (transformed) {
        acc.push(transformed);
      }
      return acc;
    }, []);
  }, [currentUserId, feedItems]);
  const filteredItems = React.useMemo(() => {
    return transformedItems.filter(item => {
      if ((item.type === 'comment' || item.type === 'annotation') && item.isResolved && !showResolved) {
        return false;
      }
      if (showOnlyMentionsMe && currentUserId) {
        if (item.type === 'comment' || item.type === 'annotation') {
          const hasMention = item.messages.some(msg => msg.message?.content?.some(paragraph => paragraph.content?.some(node => node.type === 'mention' && node.attrs?.mentionedUserId === currentUserId)));
          if (!hasMention) return false;
        }
        if (item.type === 'task') {
          const isAssigned = item.props.assignees.some(a => a.id === currentUserId);
          if (!isAssigned) return false;
        }
        if (item.type === 'version' || item.type === 'app_activity') {
          return false;
        }
      }
      return true;
    });
  }, [currentUserId, showOnlyMentionsMe, showResolved, transformedItems]);
  React.useEffect(() => {
    const alreadyScrolledToThisEntry = scrolledEntryIdRef.current === activeFeedEntryId;
    if (!activeFeedEntryId || !scrollHandle || alreadyScrolledToThisEntry) {
      return;
    }
    const didScroll = scrollHandle.scrollTo(activeFeedEntryId);
    if (didScroll) {
      scrolledEntryIdRef.current = activeFeedEntryId;
    }
  }, [activeFeedEntryId, filteredItems, scrollHandle]);
  React.useEffect(() => {
    const hasDeepLink = Boolean(activeFeedEntryId);
    if (hasScrolledToEndRef.current || hasDeepLink || !scrollHandle || filteredItems.length === 0) {
      return;
    }
    const lastItemId = filteredItems[filteredItems.length - 1].id;
    const didScroll = scrollHandle.scrollTo(lastItemId);
    if (didScroll) {
      hasScrolledToEndRef.current = true;
    }
  }, [activeFeedEntryId, filteredItems, scrollHandle]);

  // Scroll only to comments/annotations the current user authored after the post
  // snapshot, so a concurrent push from another user doesn't hijack the viewport.
  React.useEffect(() => {
    const knownIds = knownIdsBeforePostRef.current;
    if (!knownIds || !scrollHandle || !currentUserId) return;
    const newItem = filteredItems.find(item => {
      if (knownIds.has(item.id)) return false;
      if (item.type !== 'comment' && item.type !== 'annotation') return false;
      const author = item.messages[0]?.author;
      return author ? String(author.id) === currentUserId : false;
    });
    if (!newItem) return;
    if (scrollHandle.scrollTo(newItem.id)) {
      knownIdsBeforePostRef.current = null;
    }
  }, [currentUserId, filteredItems, scrollHandle]);
  const handleCommentPost = React.useCallback(async content => {
    if (!onCommentCreate) return;
    const serialized = serializeEditorContent(content);
    if (!serialized || !serialized.text) return;
    try {
      const snapshot = new Set(filteredItems.map(item => item.id));
      await onCommentCreate(serialized.text, serialized.hasMention);
      knownIdsBeforePostRef.current = snapshot;
    } catch (error) {
      // eslint-disable-next-line no-console
      console.error('ActivityFeedV2: failed to post comment', error);
    }
  }, [filteredItems, onCommentCreate]);
  return /*#__PURE__*/React.createElement("div", {
    className: "bcs-NewActivityFeed"
  }, /*#__PURE__*/React.createElement(ActivityFeed.Root, {
    mentionContext: mentionContext,
    scrollTo: scrollHandle
  }, /*#__PURE__*/React.createElement(ActivityFeed.Header, {
    title: headerTitle
  }, /*#__PURE__*/React.createElement(ActivityFeed.Header.Actions, null, /*#__PURE__*/React.createElement(ActivityFeed.Header.FilterMenu, null, /*#__PURE__*/React.createElement(ActivityFeed.Header.ShowResolvedOption, {
    checked: showResolved,
    onCheckedChange: handleShowResolvedChange
  }), /*#__PURE__*/React.createElement(ActivityFeed.Header.MentionMeOption, {
    checked: showOnlyMentionsMe,
    hasTasks: hasTasks,
    onCheckedChange: handleShowOnlyMentionsMeChange
  })), hasTasks && /*#__PURE__*/React.createElement(ActivityFeed.Header.TaskButton, {
    disabled: isDisabled,
    onMenuItemClick: selectedTaskType => {
      setTaskType(selectedTaskType);
      setIsTaskFormOpen(true);
    }
  }))), feedItems && /*#__PURE__*/React.createElement("div", {
    className: "bcs-NewActivityFeed-list"
  }, /*#__PURE__*/React.createElement(ActivityFeed.List, null, filteredItems.map(item => /*#__PURE__*/React.createElement(FeedItemRow, {
    key: item.id,
    currentUserId: currentUserId,
    isDisabled: isDisabled,
    item: item,
    onAnnotationCopyLink: onAnnotationCopyLink,
    onAnnotationDelete: onAnnotationDelete,
    onAnnotationEdit: onAnnotationEdit,
    onAnnotationSelect: onAnnotationSelect,
    onAnnotationStatusChange: onAnnotationStatusChange,
    onCommentCopyLink: onCommentCopyLink,
    onCommentDelete: onCommentDelete,
    onCommentUpdate: onCommentUpdate,
    onReplyCreate: onReplyCreate,
    onReplyDelete: onReplyDelete,
    onReplyUpdate: onReplyUpdate,
    onTaskAssignmentUpdate: onTaskAssignmentUpdate,
    onTaskDelete: onTaskDelete,
    onTaskEdit: onTaskUpdate ? handleTaskEdit : undefined,
    onTaskView: onTaskView,
    onVersionHistoryClick: onVersionHistoryClick,
    userSelectorProps: userSelectorProps
  })))), /*#__PURE__*/React.createElement("div", {
    className: "bcs-NewActivityFeed-editor"
  }, /*#__PURE__*/React.createElement(ActivityFeed.Editor, {
    disableComponent: isDisabled || !currentUser,
    onPost: handleCommentPost,
    userSelectorProps: userSelectorProps
  }))), /*#__PURE__*/React.createElement(TaskModal, {
    editMode: editingTask ? TASK_EDIT_MODE_EDIT : undefined,
    error: taskError,
    isTaskFormOpen: isTaskFormOpen,
    onModalClose: handleTaskModalClose,
    onSubmitError: setTaskError,
    onSubmitSuccess: handleTaskModalClose,
    taskFormProps: editingTask ? {
      approvers: editingAssignees?.entries ?? [],
      approverSelectorContacts,
      completionRule: editingTask.completion_rule,
      createTask: noop,
      dueDate: editingTask.due_at,
      editTask: onTaskUpdate,
      getApproverWithQuery,
      getAvatarUrl,
      id: editingTask.id,
      message: editingTask.description
    } : {
      approvers: [],
      approverSelectorContacts,
      completionRule: TASK_COMPLETION_RULE_ALL,
      createTask,
      getApproverWithQuery,
      getAvatarUrl,
      id: '',
      message: ''
    },
    taskType: taskType
  }));
};
export default ActivityFeedV2;
//# sourceMappingURL=ActivityFeedV2.js.map