import classNames from 'classnames';
import _ from 'lodash';
import { PropTypes } from 'react';

import InlineDialog, { InlineDialogTrigger } from '../aui-react/inline-dialog';
import models from '../models/models';
import ReviewerAvatar from '../reviewer-avatar/reviewer-avatar';
import SelfReviewer from '../self-reviewer/self-reviewer';

const propTypes = {
    avatarSize: PropTypes.string,
    currentUserAsReviewer: PropTypes.object,
    currentUserAvatarSize: PropTypes.string,
    dialogReviewersAsTooltip: PropTypes.bool,
    isWatching: PropTypes.bool,
    maxOpen: PropTypes.number,
    menuId: PropTypes.string.isRequired,
    onSelfClick: PropTypes.func,
    permissionToReview: PropTypes.bool.isRequired,
    pullRequestIsOpen: PropTypes.bool.isRequired,
    reverse: PropTypes.bool,
    reviewers: PropTypes.array.isRequired,
    triggerClass: PropTypes.string,
};

const approvalOrder = {
    APPROVED: 1,
    NEEDS_WORK: 2,
    UNAPPROVED: 3,
};

const statusMap = {
    [models.ApprovalState.APPROVED]: AJS.I18n.getText('bitbucket.component.avatar.badge.approved'),
    [models.ApprovalState.NEEDS_WORK]: AJS.I18n.getText('bitbucket.component.avatar.badge.needs.work'),
};

function sortReviewers(reviewers) {
    return reviewers.slice().sort((a, b) => {
        return (approvalOrder[a.state] - approvalOrder[b.state]) ||
            a.user.display_name.localeCompare(b.user.display_name);
    });
}

/**
 * Displays a list of avatars
 *
 * @param {Object} props - Component properties
 * @param {Array} props.reviewers - The reviewers
 * @param {string} props.menuId - ID for the overflow dialog
 * @param {string?} props.triggerClass - Additional classes for the overflow dialog trigger
 * @param {number?} props.maxOpen - Maximum number of reviewers to show before overflow
 * @param {string?} props.avatarSize - Avatar size to show reviewers at
 * @param {boolean?} props.reverse - Order to show reviewers
 * @returns {ReactElement} - rendered component
 */
const ReviewerAvatarList = props => {
    const sortedReviewers = sortReviewers(props.reviewers);
    const currentUserIndex = (props.currentUserAsReviewer) ?
        _.findIndex(sortedReviewers, user => {
            return user.user.name === (props.currentUserAsReviewer.name || props.currentUserAsReviewer.user.name);
        }) :
        -1;

    const showingSelfReviewer = props.permissionToReview && props.pullRequestIsOpen;
    const maxOpen = (showingSelfReviewer) ? props.maxOpen - 1 : props.maxOpen;
    if (currentUserIndex > -1) {
        // remove current user from ReviewerAvatarList,
        // instead shown in SelfReviewer component
        const currentUser = sortedReviewers.splice(currentUserIndex, 1)[0];

        // put the currentUser in front when
        // SelfReviewer component is hidden
        // or if we want to change the current user's avatar size
        if (!showingSelfReviewer || props.currentUserAvatarSize) {
            sortedReviewers.unshift(currentUser);
        }
    }

    let visibleReviewers;
    let dialogReviewers;
    if (sortedReviewers.length > maxOpen) {
        visibleReviewers = sortedReviewers.slice(0, maxOpen - 1);
        dialogReviewers = sortedReviewers.slice(maxOpen - 1);
    } else {
        visibleReviewers = sortedReviewers;
        dialogReviewers = [];
    }

    const visibleAvatars = visibleReviewers.map(reviewer => {
        return (
            <ReviewerAvatar
                reviewer={reviewer}
                key={reviewer.user.name}
                avatarSize={(props.currentUserAsReviewer && props.currentUserAvatarSize) &&
                    (reviewer.user.name === props.currentUserAsReviewer.name) ?
                    props.currentUserAvatarSize :
                    'small'
                }
            />);
    });
    const children = visibleAvatars.slice();

    if (showingSelfReviewer) {
        children.unshift(
            <SelfReviewer
                removeSelfModalId="remove-self-modal"
                currentUserAsReviewer={props.currentUserAsReviewer}
                isWatching={props.isWatching}
                key="self_reviewer"
                onSelfClick={props.onSelfClick}
            />
        );
    }

    if (dialogReviewers.length) {
        if (props.dialogReviewersAsTooltip) {
            let tooltipString = '';
            dialogReviewers.map((reviewer, i, arr) => {
                tooltipString += reviewer.user.display_name;
                if (reviewer.state !== models.ApprovalState.UNAPPROVED) {
                    tooltipString += ' (' + statusMap[reviewer.state] + ')';
                }
                if ((i + 1) < arr.length) {
                    tooltipString += '<br>';
                }
            });
            children.push(
                <button
                    className="overflow-reviewers-trigger overflow-reviewers-tooltip aui-button aui-button-subtle"
                    key="overflow-reviewers-tooltip"
                    title={tooltipString}
                    ref={el => AJS.$(el).tooltip({
                        html: true,
                    })}
                >
                    +{dialogReviewers.length}
                </button>
            );
        } else {
            children.push(
                <InlineDialogTrigger
                    key="trigger"
                    dialogId={props.menuId}
                    className={classNames('aui-button-subtle overflow-reviewers-trigger', props.triggerClass)}
                >
                    +{dialogReviewers.length}
                </InlineDialogTrigger>
            );
            children.push(
                <InlineDialog
                    key="dialog"
                    id={props.menuId}
                    className="overflow-reviewers"
                    alignment={props.reverse ? 'left top' : 'bottom right'}
                >
                    <div className="avatar-dropdown">
                        <ul className="aui-list-truncate">
                            {dialogReviewers.map(reviewer => {
                                return <li key={reviewer.user.name}><ReviewerAvatar reviewer={reviewer} tooltip={false} nameOnly withName /></li>;
                            })}
                        </ul>
                    </div>
                </InlineDialog>
            );
        }
    }

    return (
        <div className={classNames('reviewer-avatar-list', { reviewing: props.currentUserAsReviewer, reversed: props.reverse })}>
            {props.reverse ? children.reverse() : children}
        </div>
    );
};

ReviewerAvatarList.propTypes = propTypes;
export default ReviewerAvatarList;
