import React from 'react';
import PropTypes from 'prop-types';
import { compose, gql } from 'react-apollo';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import UserDetail from '../components/UserDetail';
import withQuery from 'coral-framework/hocs/withQuery';
import { withRouter } from 'react-router';
import {
  getDefinitionName,
  getSlotFragmentSpreads,
} from 'coral-framework/utils';
import {
  viewUserDetail,
  hideUserDetail,
  changeTab,
  clearUserDetailSelections,
  toggleSelectCommentInUserDetail,
  toggleSelectAllCommentInUserDetail,
} from 'coral-admin/src/actions/userDetail';
import {
  withSetCommentStatus,
  withUnbanUser,
  withUnsuspendUser,
  withRemoveAlwaysPremodUser,
  withRejectUsername,
  withPostFlag,
} from 'coral-framework/graphql/mutations';
import UserDetailComment from './UserDetailComment';
import update from 'immutability-helper';
import { showBanUserDialog } from 'actions/banUserDialog';
import { showAlwaysPremodUserDialog } from 'actions/alwaysPremodUserDialog';
import { showSuspendUserDialog } from 'actions/suspendUserDialog';
import { showRejectUsernameDialog } from 'actions/rejectUsernameDialog';

const commentConnectionFragment = gql`
  fragment CoralAdmin_UserDetail_CommentConnection on CommentConnection {
    nodes {
      ...${getDefinitionName(UserDetailComment.fragments.comment)}
    }
    hasNextPage
    startCursor
    endCursor
  }
  ${UserDetailComment.fragments.comment}
`;

const slots = ['userProfile'];

class UserDetailContainer extends React.Component {
  isLoadingMore = false;

  // status can be 'ACCEPTED' or 'REJECTED'
  bulkSetCommentStatus = async status => {
    const changes = this.props.selectedCommentIds.map(commentId => {
      return this.props.setCommentStatus({ commentId, status });
    });

    await Promise.all(changes);
    this.props.clearUserDetailSelections(); // un-select everything
  };

  bulkReject = () => {
    return this.bulkSetCommentStatus('REJECTED');
  };

  bulkAccept = () => {
    return this.bulkSetCommentStatus('ACCEPTED');
  };

  acceptComment = ({ commentId }) => {
    return this.props.setCommentStatus({ commentId, status: 'ACCEPTED' });
  };

  rejectComment = ({ commentId }) => {
    return this.props.setCommentStatus({ commentId, status: 'REJECTED' });
  };

  loadMore = () => {
    if (this.isLoadingMore) {
      return;
    }

    this.isLoadingMore = true;
    const variables = {
      limit: 10,
      cursor: this.props.root.comments.endCursor,
      author_id: this.props.data.variables.author_id,
      statuses: this.props.data.variables.statuses,
    };
    this.props.data
      .fetchMore({
        query: LOAD_MORE_QUERY,
        variables,
        updateQuery: (prev, { fetchMoreResult: { comments } }) => {
          return update(prev, {
            comments: {
              nodes: { $push: comments.nodes },
              hasNextPage: { $set: comments.hasNextPage },
              startCursor: { $set: comments.startCursor },
              endCursor: { $set: comments.endCursor },
            },
          });
        },
      })
      .then(() => {
        this.isLoadingMore = false;
      })
      .catch(err => {
        this.isLoadingMore = false;
        throw err;
      });
  };

  componentWillReceiveProps(next) {
    if (this.props.userId === null && next.userId) {
      next.data.refetch();
    }
  }

  render() {
    if (!this.props.userId) {
      return null;
    }

    const loading = this.props.data.loading;

    return (
      <UserDetail
        bulkReject={this.bulkReject}
        bulkAccept={this.bulkAccept}
        changeTab={this.props.changeTab}
        toggleSelect={this.props.toggleSelectCommentInUserDetail}
        toggleSelectAll={this.props.toggleSelectAllCommentInUserDetail}
        acceptComment={this.acceptComment}
        rejectComment={this.rejectComment}
        loading={loading}
        error={this.props.data && this.props.data.error}
        loadMore={this.loadMore}
        rejectUsername={this.props.rejectUsername}
        {...this.props}
      />
    );
  }
}

UserDetailContainer.propTypes = {
  changeTab: PropTypes.func,
  toggleSelectCommentInUserDetail: PropTypes.func,
  toggleSelectAllCommentInUserDetail: PropTypes.func,
  data: PropTypes.object,
  root: PropTypes.object,
  setCommentStatus: PropTypes.func,
  clearUserDetailSelections: PropTypes.func,
  selectedCommentIds: PropTypes.array,
  unbanUser: PropTypes.func.isRequired,
  unsuspendUser: PropTypes.func.isRequired,
  removeAlwaysPremodUser: PropTypes.func.isRequired,
  rejectUsername: PropTypes.func.isRequired,
  userId: PropTypes.string,
};

const LOAD_MORE_QUERY = gql`
  query CoralAdmin_Moderation_LoadMore(
    $limit: Int = 10
    $cursor: Cursor
    $author_id: ID!
    $statuses: [COMMENT_STATUS!]
  ) {
    comments(
      query: {
        limit: $limit
        cursor: $cursor
        author_id: $author_id
        statuses: $statuses
      }
    ) {
      ...CoralAdmin_UserDetail_CommentConnection
    }
  }
  ${commentConnectionFragment}
`;

export const withUserDetailQuery = withQuery(
  gql`
  query CoralAdmin_UserDetail($author_id: ID!, $statuses: [COMMENT_STATUS!]) {
    user(id: $author_id) {
      id
      username
      created_at
      email
      profiles {
        id
        provider
      }
      reliable {
        commenter
        commenterKarma
      }
      state {
        status {
          suspension {
            until
            history {
              until
              created_at
              assigned_by {
                id
                username
              }
            }
          }
          banned {
            status
            history {
              status
              assigned_by {
                id
                username
              }
              created_at
            }
          }
          alwaysPremod {
            status
            history {
              status
              assigned_by {
                id
                username
              }
              created_at
            }
          },
          username {
            status
            history {
              status
              assigned_by {
                id
                username
              }
              created_at
            }
          }
        }
      }
      ${getSlotFragmentSpreads(slots, 'user')}
    }
    settings {
      karmaThresholds {
        comment {
          reliable
          unreliable
        }
      }
    }
    me {
      id
    }
    totalComments: commentCount(query: {author_id: $author_id, statuses: []})
    rejectedComments: commentCount(query: {author_id: $author_id, statuses: [REJECTED]})
    comments: comments(query: {
      author_id: $author_id,
      statuses: $statuses
    }) {
      ...CoralAdmin_UserDetail_CommentConnection
    }
    ...${getDefinitionName(UserDetailComment.fragments.root)}
    ${getSlotFragmentSpreads(slots, 'root')}
  }
  ${UserDetailComment.fragments.root}
  ${commentConnectionFragment}
`,
  {
    options: ({ userId, statuses }) => {
      return {
        variables: { author_id: userId, statuses },
      };
    },
    skip: ownProps => !ownProps.userId,
  }
);

const mapStateToProps = state => ({
  userId: state.userDetail.userId,
  selectedCommentIds: state.userDetail.selectedCommentIds,
  statuses: state.userDetail.statuses,
  activeTab: state.userDetail.activeTab,
  modal: state.ui.modal,
});

const mapDispatchToProps = dispatch => ({
  ...bindActionCreators(
    {
      showBanUserDialog,
      showAlwaysPremodUserDialog,
      showSuspendUserDialog,
      showRejectUsernameDialog,
      changeTab,
      clearUserDetailSelections,
      toggleSelectCommentInUserDetail,
      viewUserDetail,
      hideUserDetail,
      toggleSelectAllCommentInUserDetail,
    },
    dispatch
  ),
});

export default compose(
  connect(
    mapStateToProps,
    mapDispatchToProps
  ),
  withUserDetailQuery,
  withSetCommentStatus,
  withUnbanUser,
  withUnsuspendUser,
  withRemoveAlwaysPremodUser,
  withRejectUsername,
  withPostFlag,
  withRouter
)(UserDetailContainer);
