// eslint-disable-reason combining lots of items from store
/* eslint-disable max-params */
import {createSelector} from 'reselect';
import moment from 'moment';
import _ from 'lodash';

import {ITEM_TYPE_ACTIVITY, ITEM_TYPE_DAY_SEPARATOR, ITEM_TYPE_NEW_MESSAGE_SEPARATOR} from '@ciscospark/react-component-activity-list';

const getConversationActivities = (state) => state.conversation.get(`activities`);
const getAvatar = (state) => state.avatar;
const getUser = (state) => state.user;
const getFlags = (state) => state.flags.flags;
const getSendingActivities = (state) => state.activity;
const getLastAcknowledgedActivityId = (state) => state.conversation.get(`lastAcknowledgedActivityId`);

const VISIBLE_ACTIVITY_VERBS = {
  tombstone: {},
  share: {
    objectTypes: [`content`]
  },
  post: {
    objectTypes: [`comment`]
  },
  create: {
    objectTypes: [`conversation`]
  },
  update: {
    objectTypes: [`locusSessionSummaryParticipant`, `locusSessionSummary`]
  }
};


/**
 * This loops through our conversation activities and computes an array
 * of 'visible activities' to be used with the ActivityList component
 */
export const getActivityList = createSelector(
  [getConversationActivities, getAvatar, getUser, getSendingActivities, getFlags, getLastAcknowledgedActivityId],
  (conversationActivities, avatar, user, sendingActivities, flags, lastAcknowledgedActivityId) => {
    const avatars = avatar.get(`items`);
    const currentUser = user.get(`currentUser`);
    const inFlightActivities = sendingActivities.get(`inFlightActivities`);
    const visibleActivityList = [];
    const now = moment();
    let lastActorId, lastDay, lastVerb;
    let shouldDisplayNewMessageMarker = false;

    conversationActivities.forEach((activity) => {
      if (isActivityVisible(activity)) {
        // Insert day separator if this activity and last one happen on a different day
        const activityMoment = moment(activity.published, moment.ISO_8601);
        const activityDay = activityMoment.endOf(`day`);
        const sameDay = activityDay.diff(lastDay, `days`) === 0;
        if (lastDay && !sameDay) {
          visibleActivityList.push(
            {
              type: ITEM_TYPE_DAY_SEPARATOR,
              fromDate: lastDay,
              key: `day-separtor-${activity.id}`,
              now,
              toDate: activityDay
            }
          );
        }
        lastDay = activityDay;

        // New message marker
        if (shouldDisplayNewMessageMarker) {
          visibleActivityList.push({
            type: ITEM_TYPE_NEW_MESSAGE_SEPARATOR,
            key: `new-messages-${activity.id}`
          });
          shouldDisplayNewMessageMarker = false;
        }

        // Actual visible activity item
        // additional items don't repeat user avatar and name
        const isAdditional = sameDay && lastActorId === activity.actor.id && lastVerb === activity.verb;
        lastActorId = activity.actor.id;
        lastVerb = activity.verb;

        // eslint-disable-reason callbacks are necessary
        // eslint-disable-next-line max-nested-callbacks
        const isFlagged = flags && flags.some((flag) => flag.activityUrl === activity.url);

        // Update verbs are currently used for call data
        let callData;
        if (activity.verb === `update`) {
          callData = getCallData(activity, currentUser);
        }

        const visibleActivity = {
          type: ITEM_TYPE_ACTIVITY,
          activity: {
            ...activity,
            callData
          },
          avatarUrl: avatars.get(activity.actor.id),
          isAdditional,
          isFlagged,
          isSelf: currentUser.id === activity.actor.id
        };
        visibleActivityList.push(visibleActivity);

        // Check if this is the last read activity
        const isLastAcked = lastAcknowledgedActivityId && lastAcknowledgedActivityId === activity.id;
        const isNotSelf = currentUser.id !== activity.actor.id;
        if (isLastAcked && isNotSelf) {
          shouldDisplayNewMessageMarker = true;
        }
      }
    });

    // Create a "fake" activity to display in flight activities
    inFlightActivities.forEach((inFlightActivity) => {
      visibleActivityList.push(
        {
          type: ITEM_TYPE_ACTIVITY,
          activity: inFlightActivity,
          avatarUrl: avatars.get(currentUser.id),
          isAdditional: false,
          isFlagged: false,
          isSelf: true,
          isPending: true
        }
      );
    });

    return visibleActivityList;
  }
);

/**
 * Determines if an activity object is a visible activity
 * @param {object} activity
 * @returns {bool}
 */
function isActivityVisible(activity) {
  if (!VISIBLE_ACTIVITY_VERBS.hasOwnProperty(activity.verb)) {
    return false;
  }
  const verb = VISIBLE_ACTIVITY_VERBS[activity.verb];
  if (verb.objectTypes) {
    if (verb.objectTypes.indexOf(activity.object.objectType) === -1) {
      return false;
    }
  }
  return true;
}

/**
 * Parses call data from an activity
 * @param {object} activity
 * @param {object} currentUser
 * @returns {object}
 */
function getCallData(activity, currentUser) {
  if (activity.object.objectType !== `locusSessionSummary`) {
    return null;
  }
  // Call/Meeting update parsing
  const callObject = activity.object;
  const partner = _.find(callObject.participants.items, (p) => p.person.entryUUID !== currentUser.id);
  const me = _.find(callObject.participants.items, (p) => p.person.entryUUID === currentUser.id);

  const iDeclined = me && me.state === `DECLINED`;
  const everyBodyJoined = _.every(callObject.participants.items, (p) => p.state === `LEFT`);

  let arg;
  let status;

  if (everyBodyJoined) {
    status = `youHadACall`;
  }
  else if (iDeclined) {
    status = `youCancelledACall`;
  }
  else if (activity.actor.entryUUID === currentUser.id) {
    status = `someoneWasUnavailable`;
    arg = {name: partner.person.displayName};
  }
  else {
    status = `youMissedACall`;
  }

  // Duration
  const duration = moment.duration((callObject.duration || 0) * 1000).humanize();

  return {
    callInfo: {
      duration,
      ...arg
    },
    status
  };
}

@@ -1548,24 +1548,96 @@
 tivities%60);%0A
+    const activityFailures = sendingActivities.get(%60activityFailures%60);%0A
     const vi
@@ -4567,24 +4567,464 @@
 );%0A    %7D);%0A%0A
+    // Create a %22fake%22 activity to display failed activities%0A    activityFailures.forEach((activityFailure) =%3E %7B%0A      visibleActivityList.push(%0A        %7B%0A          type: ITEM_TYPE_ACTIVITY,%0A          activity: activityFailure,%0A          avatarUrl: avatars.get(currentUser.id),%0A          isAdditional: false,%0A          isError: true,%0A          isFlagged: false,%0A          isSelf: true,%0A          isPending: true%0A        %7D%0A      );%0A    %7D);%0A%0A
     return v

add error activities to selector