/**
 * Copyright 2017 Red Hat Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

import * as _ from 'lodash';
import { connect } from 'react-redux';
import { List, Map } from 'immutable';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Formsy from 'formsy-react';

import {
  getAvailableNodeProfiles,
  getFilteredNodes,
  getNodesOperationInProgress
} from '../../selectors/nodes';
import ConfirmationModal from '../ui/ConfirmationModal';
import FormErrorList from '../ui/forms/FormErrorList';
import NodesActions from '../../actions/NodesActions';
import NodesTable from './NodesTable';
import TagNodesModal from './tag_nodes/TagNodesModal';
import { findClosestWithAttribute } from '../utils/Dom';

const messages = defineMessages({
  introspectNodes: {
    id: 'NodesTableView.introspectNodes',
    defaultMessage: 'Introspect Nodes'
  },
  tagNodes: {
    id: 'NodesTableView.tagNodes',
    defaultMessage: 'Tag Nodes'
  },
  provideNodes: {
    id: 'NodesTableView.provideNodes',
    defaultMessage: 'Provide Nodes',
    description: '"Providing" the nodes changes the provisioning state to "available" so that ' +
      'they can be used in a deployment.'
  },
  deleteNodes: {
    id: 'NodesTableView.deleteNodes',
    defaultMessage: 'Delete Nodes'
  },
  deleteNodesModalTitle: {
    id: 'NodesTableView.deleteNodesModalTitle',
    defaultMessage: 'Delete Nodes'
  },
  deleteNodesModalMessage: {
    id: 'NodesTableView.deleteNodesModalMessage',
    defaultMessage: 'Are you sure you want to delete the selected nodes?'
  }
});

class NodesTableView extends React.Component {
  constructor() {
    super();
    this.state = {
      canSubmit: false,
      showDeleteModal: false,
      showTagNodesModal: false,
      submitParameters: {},
      submitType: 'introspect'
    };
  }

  componentDidUpdate() {
    this.invalidateForm(this.props.formFieldErrors.toJS());
  }

  canSubmit() {
    if (
      _.includes(
        _.values(this.refs.registeredNodesTableForm.getCurrentValues()),
        true
      )
    ) {
      this.enableButton();
    } else {
      this.disableButton();
    }
  }

  enableButton() {
    this.setState({ canSubmit: true });
  }

  disableButton() {
    this.setState({ canSubmit: false });
  }

  invalidateForm(formFieldErrors) {
    this.refs.registeredNodesTableForm.updateInputsWithError(formFieldErrors);
  }

  getTableActions() {
    return (
      <div className="btn-group">
        <button
          className="btn btn-default"
          type="button"
          name="introspect"
          onClick={this.multipleSubmit.bind(this)}
          disabled={
            !this.state.canSubmit || this.props.nodesOperationInProgress
          }
        >
          <FormattedMessage {...messages.introspectNodes} />
        </button>
        <button
          className="btn btn-default"
          type="button"
          name="tag"
          onClick={() => this.setState({ showTagNodesModal: true })}
          disabled={
            !this.state.canSubmit || this.props.nodesOperationInProgress
          }
        >
          <FormattedMessage {...messages.tagNodes} />
        </button>
        <button
          className="btn btn-default"
          type="button"
          name="provide"
          onClick={this.multipleSubmit.bind(this)}
          disabled={
            !this.state.canSubmit || this.props.nodesOperationInProgress
          }
        >
          <FormattedMessage {...messages.provideNodes} />
        </button>
        <button
          className="btn btn-danger"
          type="button"
          name="delete"
          onClick={() => this.setState({ showDeleteModal: true })}
          disabled={
            !this.state.canSubmit || this.props.nodesOperationInProgress
          }
        >
          <FormattedMessage {...messages.deleteNodes} />
        </button>
      </div>
    );
  }

  onTagNodesSubmit(tag) {
    this.setState(
      {
        submitType: 'tag',
        showTagNodesModal: false,
        submitParameters: { tag: tag }
      },
      this.refs.registeredNodesTableForm.submit
    );
  }

  multipleSubmit(e) {
    this.setState(
      {
        submitType: findClosestWithAttribute(e.target, 'name')
      },
      this.refs.registeredNodesTableForm.submit
    );
  }

  handleSubmit(formData, resetForm, invalidateForm) {
    this.disableButton();
    const nodeIds = _.keys(_.pickBy(formData, value => !!value));

    switch (this.state.submitType) {
      case 'introspect':
        this.props.introspectNodes(nodeIds);
        break;
      case 'tag':
        this.props.tagNodes(nodeIds, this.state.submitParameters.tag);
        this.setState({ submitParameters: {} });
        break;
      case 'provide':
        this.props.provideNodes(nodeIds);
        break;
      case 'delete':
        this.setState({ showDeleteModal: false });
        this.props.deleteNodes(nodeIds);
        break;
      default:
        break;
    }

    resetForm();
  }

  render() {
    return (
      <div>
        <Formsy.Form
          ref="registeredNodesTableForm"
          role="form"
          className="form"
          onSubmit={this.handleSubmit.bind(this)}
          onValid={this.canSubmit.bind(this)}
          onInvalid={this.disableButton.bind(this)}
        >
          <FormErrorList errors={this.props.formErrors.toJS()} />
          <NodesTable
            nodes={this.props.nodes}
            dataOperationInProgress={this.props.nodesOperationInProgress}
            nodesInProgress={this.props.nodesInProgress}
            isFetchingNodes={this.props.isFetchingNodes}
            tableActions={this.getTableActions.bind(this)}
          />
          <ConfirmationModal
            show={this.state.showDeleteModal}
            title={this.props.intl.formatMessage(
              messages.deleteNodesModalTitle
            )}
            question={this.props.intl.formatMessage(
              messages.deleteNodesModalMessage
            )}
            iconClass="pficon pficon-delete"
            confirmActionName="delete"
            onConfirm={this.multipleSubmit.bind(this)}
            onCancel={() => this.setState({ showDeleteModal: false })}
          />
          <TagNodesModal
            availableProfiles={this.props.availableProfiles.toArray()}
            onProfileSelected={this.onTagNodesSubmit.bind(this)}
            onCancel={() =>
              this.setState({ showTagNodesModal: false, submitParameters: {} })}
            show={this.state.showTagNodesModal}
          />
        </Formsy.Form>
      </div>
    );
  }
}
NodesTableView.propTypes = {
  availableProfiles: ImmutablePropTypes.list.isRequired,
  children: PropTypes.node,
  deleteNodes: PropTypes.func.isRequired,
  formErrors: ImmutablePropTypes.list,
  formFieldErrors: ImmutablePropTypes.map,
  intl: PropTypes.object,
  introspectNodes: PropTypes.func.isRequired,
  isFetchingNodes: PropTypes.bool.isRequired,
  nodes: ImmutablePropTypes.map,
  nodesInProgress: ImmutablePropTypes.set,
  nodesOperationInProgress: PropTypes.bool.isRequired,
  provideNodes: PropTypes.func.isRequired,
  tagNodes: PropTypes.func.isRequired
};
NodesTableView.defaultProps = {
  formErrors: List(),
  formFieldErrors: Map()
};

function mapStateToProps(state) {
  return {
    availableProfiles: getAvailableNodeProfiles(state),
    nodes: getFilteredNodes(state),
    nodesInProgress: state.nodes.get('nodesInProgress'),
    nodesOperationInProgress: getNodesOperationInProgress(state),
    isFetchingNodes: state.nodes.get('isFetching')
  };
}

function mapDispatchToProps(dispatch) {
  return {
    deleteNodes: nodeIds => dispatch(NodesActions.deleteNodes(nodeIds)),
    introspectNodes: nodeIds =>
      dispatch(NodesActions.startNodesIntrospection(nodeIds)),
    provideNodes: nodeIds => dispatch(NodesActions.startProvideNodes(nodeIds)),
    tagNodes: (nodeIds, tag) => dispatch(NodesActions.tagNodes(nodeIds, tag))
  };
}

export default injectIntl(
  connect(mapStateToProps, mapDispatchToProps)(NodesTableView)
);
