import React from 'react';
import { string, arrayOf, bool, func } from 'prop-types';
import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
import { dropWhile } from 'lodash';
import classNames from 'classnames';
import { Avatar, InlineTextButton } from '../../components';
import { formatDate } from '../../util/dates';
import { ensureTransaction, ensureUser, ensureListing } from '../../util/data';
import * as propTypes from '../../util/propTypes';

import css from './ActivityFeed.css';

const Message = props => {
  const { message, intl } = props;
  const todayString = intl.formatMessage({ id: 'ActivityFeed.today' });
  return (
    <div className={css.message}>
      <Avatar className={css.avatar} user={message.sender} />
      <div>
        <p className={css.messageContent}>{message.attributes.content}</p>
        <p className={css.messageDate}>{formatDate(intl, todayString, message.attributes.at)}</p>
      </div>
    </div>
  );
};

Message.propTypes = {
  message: propTypes.message.isRequired,
  intl: intlShape.isRequired,
};

const OwnMessage = props => {
  const { message, intl } = props;
  const todayString = intl.formatMessage({ id: 'ActivityFeed.today' });
  return (
    <div className={css.ownMessage}>
      <div className={css.ownMessageContentWrapper}>
        <p className={css.ownMessageContent}>{message.attributes.content}</p>
      </div>
      <p className={css.ownMessageDate}>{formatDate(intl, todayString, message.attributes.at)}</p>
    </div>
  );
};

OwnMessage.propTypes = {
  message: propTypes.message.isRequired,
  intl: intlShape.isRequired,
};

const Transition = props => {
  const { transition, currentUser, customer, provider, listingTitle, intl } = props;

  const resolveTransitionMessage = (transition, ownRole, otherUsersName, intl) => {
    const isOwnTransition = transition.by === ownRole;
    const transitionType = transition.transition;
    const displayName = otherUsersName;

    switch (transitionType) {
      case propTypes.TX_TRANSITION_PREAUTHORIZE:
        return isOwnTransition
          ? intl.formatMessage({ id: 'ActivityFeed.ownTransitionRequest' }, { listingTitle })
          : intl.formatMessage(
              { id: 'ActivityFeed.transitionRequest' },
              { displayName, listingTitle }
            );
      case propTypes.TX_TRANSITION_ACCEPT:
        return isOwnTransition
          ? intl.formatMessage({ id: 'ActivityFeed.ownTransitionAccept' })
          : intl.formatMessage({ id: 'ActivityFeed.transitionAccept' }, { displayName });
      case propTypes.TX_TRANSITION_DECLINE:
        return isOwnTransition
          ? intl.formatMessage({ id: 'ActivityFeed.ownTransitionDecline' })
          : intl.formatMessage({ id: 'ActivityFeed.transitionDecline' }, { displayName });
      case propTypes.TX_TRANSITION_AUTO_DECLINE:
        return ownRole === propTypes.TX_TRANSITION_ACTOR_PROVIDER
          ? intl.formatMessage({ id: 'ActivityFeed.ownTransitionAutoDecline' })
          : intl.formatMessage({ id: 'ActivityFeed.transitionAutoDecline' }, { displayName });
      case propTypes.TX_TRANSITION_MARK_DELIVERED:
        return intl.formatMessage({ id: 'ActivityFeed.transitionComplete' });
      case propTypes.TX_TRANSITION_CANCEL:
        return intl.formatMessage({ id: 'ActivityFeed.transitionCancel' });

      default:
        return '';
    }
  };

  const ownRole =
    currentUser.id.uuid === customer.id.uuid
      ? propTypes.TX_TRANSITION_ACTOR_CUSTOMER
      : propTypes.TX_TRANSITION_ACTOR_PROVIDER;

  const otherUsersName =
    ownRole === propTypes.TX_TRANSITION_ACTOR_CUSTOMER
      ? provider.attributes.profile.displayName
      : customer.attributes.profile.displayName;

  const transitionMessage = resolveTransitionMessage(transition, ownRole, otherUsersName, intl);
  const todayString = intl.formatMessage({ id: 'ActivityFeed.today' });

  return (
    <div className={css.transition}>
      <div className={css.bullet}>
        <p className={css.transitionContent}>•</p>
      </div>
      <div>
        <p className={css.transitionContent}>{transitionMessage}</p>
        <p className={css.transitionDate}>{formatDate(intl, todayString, transition.at)}</p>
      </div>
    </div>
  );
};

Transition.propTypes = {
  transition: propTypes.txTransition.isRequired,
  currentUser: propTypes.currentUser.isRequired,
  customer: propTypes.user.isRequired,
  provider: propTypes.user.isRequired,
  listingTitle: string.isRequired,
  intl: intlShape.isRequired,
};

const EmptyTransition = () => {
  return (
    <div className={css.transition}>
      <div className={css.bullet}>
        <p className={css.transitionContent}>•</p>
      </div>
      <div>
        <p className={css.transitionContent} />
        <p className={css.transitionDate} />
      </div>
    </div>
  );
};

const isMessage = item => item && item.type === 'message';

// Compare function for sorting an array containint messages and transitions
const compareItems = (a, b) => {
  const itemDate = item => (isMessage(item) ? item.attributes.at : item.at);
  return itemDate(a) - itemDate(b);
};

const organizedItems = (messages, transitions, hideOldTransitions) => {
  const items = messages.concat(transitions).sort(compareItems);
  if (hideOldTransitions) {
    // Hide transitions that happened before the oldest message. Since
    // we have older items (messages) that we are not showing, seeing
    // old transitions would be confusing.
    return dropWhile(items, i => !isMessage(i));
  } else {
    return items;
  }
};

export const ActivityFeedComponent = props => {
  const {
    rootClassName,
    className,
    messages,
    transaction,
    currentUser,
    hasOlderMessages,
    onShowOlderMessages,
    fetchMessagesInProgress,
    intl,
  } = props;
  const classes = classNames(rootClassName || css.root, className);

  const currentTransaction = ensureTransaction(transaction);
  const transitions = currentTransaction.attributes.transitions
    ? currentTransaction.attributes.transitions
    : [];
  const currentCustomer = ensureUser(currentTransaction.customer);
  const currentProvider = ensureUser(currentTransaction.provider);
  const currentListing = ensureListing(currentTransaction.listing);

  const transitionsAvailable = !!(
    currentUser &&
    currentUser.id &&
    currentCustomer.id &&
    currentProvider.id
  );

  // combine messages and transaction transitions
  const items = organizedItems(messages, transitions, hasOlderMessages || fetchMessagesInProgress);

  const transitionComponent = transition => {
    if (transitionsAvailable) {
      return (
        <Transition
          transition={transition}
          currentUser={currentUser}
          customer={currentCustomer}
          provider={currentProvider}
          listingTitle={currentListing.attributes.title}
          intl={intl}
        />
      );
    } else {
      return <EmptyTransition />;
    }
  };

  const messageComponent = message => {
    const isOwnMessage =
      message.sender &&
      message.sender.id &&
      currentUser &&
      currentUser.id &&
      message.sender.id.uuid === currentUser.id.uuid;
    if (isOwnMessage) {
      return <OwnMessage message={message} intl={intl} />;
    }
    return <Message message={message} intl={intl} />;
  };

  const messageListItem = message => {
    return (
      <li id={`msg-${message.id.uuid}`} key={message.id.uuid} className={css.messageItem}>
        {messageComponent(message)}
      </li>
    );
  };

  const transitionListItem = transition => {
    return (
      <li key={transition.transition} className={css.transitionItem}>
        {transitionComponent(transition)}
      </li>
    );
  };

  return (
    <ul className={classes}>
      {hasOlderMessages ? (
        <li className={css.showOlderWrapper} key="show-older-messages">
          <InlineTextButton className={css.showOlderButton} onClick={onShowOlderMessages}>
            <FormattedMessage id="ActivityFeed.showOlderMessages" />
          </InlineTextButton>
        </li>
      ) : null}
      {items.map(item => {
        if (isMessage(item)) {
          return messageListItem(item);
        } else {
          return transitionListItem(item);
        }
      })}
    </ul>
  );
};

ActivityFeedComponent.defaultProps = {
  rootClassName: null,
  className: null,
};

ActivityFeedComponent.propTypes = {
  rootClassName: string,
  className: string,

  currentUser: propTypes.currentUser,
  transaction: propTypes.transaction,
  messages: arrayOf(propTypes.message),
  hasOlderMessages: bool.isRequired,
  onShowOlderMessages: func.isRequired,
  fetchMessagesInProgress: bool.isRequired,

  // from injectIntl
  intl: intlShape.isRequired,
};

const ActivityFeed = injectIntl(ActivityFeedComponent);

export default ActivityFeed;
