/**
 * Configure content rule component.
 * @module components/manage/Controlpanels/Rules/ConfigureRule
 */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { Link } from 'react-router-dom';
import { getBaseUrl, getParentUrl } from '@plone/volto/helpers/Url/Url';
import Helmet from '@plone/volto/helpers/Helmet/Helmet';
import { createPortal } from 'react-dom';
import {
  Button,
  Card,
  Container,
  Dropdown,
  Grid,
  Segment,
} from 'semantic-ui-react';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import Icon from '@plone/volto/components/theme/Icon/Icon';
import Toolbar from '@plone/volto/components/manage/Toolbar/Toolbar';
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
import {
  getControlPanelRule,
  removeCondition,
  addCondition,
  editCondition,
  removeAction,
  addAction,
  editAction,
  getCondition,
  getAction,
  moveRuleCondition,
  moveRuleAction,
} from '@plone/volto/actions/rules/rules';
import { toast } from 'react-toastify';
import Toast from '@plone/volto/components/manage/Toast/Toast';

import backSVG from '@plone/volto/icons/back.svg';
import upSVG from '@plone/volto/icons/up.svg';
import downSVG from '@plone/volto/icons/down.svg';
import VariableModal from './components/VariableModal';

const messages = defineMessages({
  back: {
    id: 'Back',
    defaultMessage: 'Back',
  },
  configRule: {
    id: 'Configure content rule',
    defaultMessage: 'Configure content rule',
  },
  success: {
    id: 'Success',
    defaultMessage: 'Success',
  },
  deleteCondition: {
    id: 'Delete condition',
    defaultMessage: 'Condition deleted',
  },
  addCondition: {
    id: 'Add condition',
    defaultMessage: 'Condition added',
  },
  deleteAction: {
    id: 'Delete action',
    defaultMessage: 'Action deleted',
  },
  addAction: {
    id: 'Add action',
    defaultMessage: 'Action added',
  },
  editAction: {
    id: 'Action changed',
    defaultMessage: 'Action changed',
  },
  editCondition: {
    id: 'Condition changed',
    defaultMessage: 'Condition changed',
  },
  move: {
    id: 'Position changed',
    defaultMessage: 'Position changed',
  },
  moveUp: {
    id: 'Move up',
    defaultMessage: 'Move up',
  },
  moveDown: {
    id: 'Move down',
    defaultMessage: 'Move down',
  },
});

/**
 * ConfigureRule class.
 * @class ConfigureRule
 * @extends Component
 */
class ConfigureRule extends Component {
  /**
   * Property types.
   * @property {Object} propTypes Property types.
   * @static
   */
  static propTypes = {
    getControlPanelRule: PropTypes.func.isRequired,
    removeCondition: PropTypes.func.isRequired,
    addCondition: PropTypes.func.isRequired,
    removeAction: PropTypes.func.isRequired,
    addAction: PropTypes.func.isRequired,
    moveRuleCondition: PropTypes.func.isRequired,
    moveRuleAction: PropTypes.func.isRequired,
  };

  /**
   * Constructor
   * @method constructor
   * @param {Object} props Component properties
   * @constructs Rules
   */
  constructor(props) {
    super(props);
    this.openConditionModal = this.openConditionModal.bind(this);
    this.openActionModal = this.openActionModal.bind(this);
    this.handleConditionAdd = this.handleConditionAdd.bind(this);
    this.handleActionAdd = this.handleActionAdd.bind(this);
    this.openEditCondition = this.openEditCondition.bind(this);
    this.openEditAction = this.openEditAction.bind(this);
    this.handleEditCondition = this.handleEditCondition.bind(this);
    this.handleEditAction = this.handleEditAction.bind(this);

    this.state = {
      isClient: false,
      openModal: false,
      selConditionToAdd: '',
      selActionToAdd: '',
      selConditionToEdit: '',
      selActionToEdit: '',
      conditionFormData: '',
      actionFormData: '',
    };
  }

  /**
   * Component did mount
   * @method componentDidMount
   * @returns {undefined}
   */
  componentDidMount() {
    this.setState({ isClient: true });
    this.props.getControlPanelRule(
      getBaseUrl(this.props.pathname),
      this.props?.match?.params?.id,
    );
  }

  /**
   * Component did mount
   * @method componentDidUpdate
   * @returns {undefined}
   */
  componentDidUpdate(prevProps, prevState) {
    if (
      this.state.selConditionToEdit &&
      prevState.selConditionToEdit !== this.state.selConditionToEdit
    ) {
      this.props.getCondition(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
        this.state.selConditionToEdit.idx,
      );
    }
    if (
      this.props?.rule?.condition &&
      this.props?.rule?.condition !== prevProps?.rule.condition
    ) {
      const conditionFormData = this.props?.rule?.condition;
      this.setState({ conditionFormData });
    }
    if (
      this.state.selActionToEdit &&
      prevState.selActionToEdit !== this.state.selActionToEdit
    ) {
      this.props.getAction(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
        this.state.selActionToEdit.idx,
      );
    }
    if (
      this.props?.rule?.action &&
      this.props?.rule?.action !== prevProps?.rule.action
    ) {
      const actionFormData = this.props?.rule?.action;
      this.setState({ actionFormData });
    }
  }

  /**
   * Component will receive props
   * @method componentWillReceiveProps
   * @param {Object} nextProps Next properties
   * @returns {undefined}
   */
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (this.props.rule.move.loading && nextProps.rule.move.loaded) {
      toast.success(
        <Toast
          success
          title={this.props.intl.formatMessage(messages.success)}
          content={this.props.intl.formatMessage(messages.move)}
        />,
      );
      this.props.getControlPanelRule(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
      );
    }
    if (
      this.props.rule.deletecondition.loading &&
      nextProps.rule.deletecondition.loaded
    ) {
      toast.success(
        <Toast
          success
          title={this.props.intl.formatMessage(messages.success)}
          content={this.props.intl.formatMessage(messages.deleteCondition)}
        />,
      );
      this.props.getControlPanelRule(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
      );
    }
    if (
      this.props.rule.editcondition.loading &&
      nextProps.rule.editcondition.loaded
    ) {
      toast.success(
        <Toast
          success
          title={this.props.intl.formatMessage(messages.success)}
          content={this.props.intl.formatMessage(messages.editCondition)}
        />,
      );
      this.props.getControlPanelRule(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
      );
    }
    if (
      this.props.rule.editaction.loading &&
      nextProps.rule.editaction.loaded
    ) {
      toast.success(
        <Toast
          success
          title={this.props.intl.formatMessage(messages.success)}
          content={this.props.intl.formatMessage(messages.editAction)}
        />,
      );
      this.props.getControlPanelRule(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
      );
    }
    if (
      this.props.rule.addcondition.loading &&
      nextProps.rule.addcondition.loaded
    ) {
      toast.success(
        <Toast
          success
          title={this.props.intl.formatMessage(messages.success)}
          content={this.props.intl.formatMessage(messages.addCondition)}
        />,
      );
      this.props.getControlPanelRule(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
      );
    }
    if (
      this.props.rule.deleteaction.loading &&
      nextProps.rule.deleteaction.loaded
    ) {
      toast.success(
        <Toast
          success
          title={this.props.intl.formatMessage(messages.success)}
          content={this.props.intl.formatMessage(messages.deleteAction)}
        />,
      );
      this.props.getControlPanelRule(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
      );
    }
    if (this.props.rule.addaction.loading && nextProps.rule.addaction.loaded) {
      toast.success(
        <Toast
          success
          title={this.props.intl.formatMessage(messages.success)}
          content={this.props.intl.formatMessage(messages.addAction)}
        />,
      );
      this.props.getControlPanelRule(
        getBaseUrl(this.props.pathname),
        this.props?.match?.params?.id,
      );
    }
  }

  /**
   * Back/Cancel handler
   * @method onCancel
   * @returns {undefined}
   */
  onCancel() {
    this.props.history.push(getParentUrl(getParentUrl(this.props.pathname)));
  }

  /**
   * Remove condition handler
   * @method handleRemoveCondition
   * @returns {undefined}
   */
  handleRemoveCondition(conditionId) {
    const ruleId = this.props?.match?.params?.id;
    this.props.removeCondition(
      getBaseUrl(this.props.pathname),
      ruleId,
      conditionId,
    );
  }

  /**
   * Edit condition handler
   * @method handleEditCondition
   * @returns {undefined}
   */
  handleEditCondition(val) {
    const ruleId = this.props?.match?.params?.id;
    if (this.state.selConditionToEdit) {
      this.props.editCondition(
        getBaseUrl(this.props.pathname),
        ruleId,
        val,
        this.state.selConditionToEdit.idx,
      );
    }
  }

  /**
   * Edit action handler
   * @method handleEditAction
   * @returns {undefined}
   */
  handleEditAction(val) {
    const ruleId = this.props?.match?.params?.id;
    if (this.state.selActionToEdit) {
      this.props.editAction(
        getBaseUrl(this.props.pathname),
        ruleId,
        val,
        this.state.selActionToEdit.idx,
      );
    }
  }

  /**
   * open modal edit condition handler
   * @method openEditCondition
   * @returns {undefined}
   */
  openEditCondition(cond_id) {
    this.setState({
      selConditionToEdit: cond_id,
      openModal: true,
      selActionToEdit: '',
    });
  }

  /**
   * open modal edit action handler
   * @method openEditAction
   * @returns {undefined}
   */
  openEditAction(action_id) {
    this.setState({
      selActionToEdit: action_id,
      openModal: true,
      selConditionToEdit: '',
    });
  }

  /**
   * Add condition handler
   * @method openConditionModal
   * @returns {undefined}
   */
  openConditionModal() {
    if (this.state.selConditionToAdd) {
      this.setState({ openModal: true });
    }
  }

  /**
   * Condition save handler
   * @method handleConditionAdd
   * @returns {undefined}
   */
  handleConditionAdd(val) {
    const ruleId = this.props?.match?.params?.id;
    this.props.addCondition(getBaseUrl(this.props.pathname), ruleId, val);
    this.setState({ selConditionToAdd: '' });
  }

  /**
   * Add action handler
   * @method openActionModal
   * @returns {undefined}
   */
  openActionModal() {
    this.setState({ openModal: true });
  }

  /**
   * Action save handler
   * @method handleActionAdd
   * @returns {undefined}
   */
  handleActionAdd(val) {
    const ruleId = this.props?.match?.params?.id;
    this.props.addAction(getBaseUrl(this.props.pathname), ruleId, val);
    this.setState({ selConditionToAdd: '' });
  }

  /**
   * Remove action handler
   * @method handleRemoveAction
   * @returns {undefined}
   */
  handleRemoveAction(actionId) {
    const ruleId = this.props?.match?.params?.id;
    this.props.removeAction(getBaseUrl(this.props.pathname), ruleId, actionId);
  }

  /**
   * Move action handler
   * @method handleMoveAction
   * @returns {undefined}
   */
  handleMoveAction(action, direction) {
    const ruleId = this.props?.match?.params?.id;
    this.props.moveRuleAction(
      getBaseUrl(this.props.pathname),
      {
        'form.button.Move': direction === 'up' ? '_move_up' : '_move_down',
      },
      ruleId,
      action,
    );
  }

  /**
   * Move action handler
   * @method handleMoveCondition
   * @returns {undefined}
   */
  handleMoveCondition(condition, direction) {
    const ruleId = this.props?.match?.params?.id;
    this.props.moveRuleCondition(
      getBaseUrl(this.props.pathname),
      {
        'form.button.Move': direction === 'up' ? '_move_up' : '_move_down',
      },
      ruleId,
      condition,
    );
  }
  /**
   * Render method.
   * @method render
   * @returns {string} Markup for the component.
   */
  render() {
    const { item = {} } = this.props.rule || {};
    const {
      actions = [],
      addable_actions = [],
      addable_conditions = [],
      assignments = [],
      conditions = [],
      title = '',
    } = item;
    const conditions_options = addable_conditions.map((cond) => {
      return { key: cond.title, text: cond.title, value: cond };
    });

    const actions_options = addable_actions.map((act) => {
      return { key: act.title, text: act.title, value: act };
    });
    return (
      <div id="page-rule-configure">
        <Helmet title={this.props.intl.formatMessage(messages.configRule)} />
        <Container>
          <article id="content">
            <Segment.Group raised>
              <Segment className="primary">
                <FormattedMessage
                  id="Configure Content Rule: {title}"
                  defaultMessage="Configure Content Rule: {title}"
                  values={{ title: <q>{title}</q> }}
                />
              </Segment>
              <Segment className="secondary">
                <FormattedMessage
                  id="Rules execute when a triggering event occurs. Rule actions will only be invoked if all the rule's conditions are met. You can add new actions and conditions using the buttons below."
                  defaultMessage="Rules execute when a triggering event occurs. Rule actions will only be invoked if all the rule's conditions are met. You can add new actions and conditions using the buttons below."
                />
              </Segment>
              <Segment>
                <Grid>
                  <Grid.Row>
                    <Grid.Column
                      mobile={16}
                      tablet={16}
                      computer={6}
                      largeScreen={6}
                    >
                      <h4>
                        <FormattedMessage
                          id="If all of the following conditions are met:"
                          defaultMessage="If all of the following conditions are met:"
                        />
                      </h4>

                      {conditions && conditions.length > 0 && (
                        <Card.Group>
                          {conditions.map((cond, i) => {
                            return (
                              <Card fluid key={i}>
                                <Card.Content>
                                  <Card.Header>
                                    <h4>{cond.title}</h4>
                                  </Card.Header>
                                  <Card.Description>
                                    {cond.summary}
                                  </Card.Description>
                                </Card.Content>
                                <Card.Content extra>
                                  <Button
                                    onClick={() => this.openEditCondition(cond)}
                                    compact
                                    size="tiny"
                                    primary
                                  >
                                    Edit
                                  </Button>
                                  <Button
                                    onClick={() =>
                                      this.handleRemoveCondition(cond.idx)
                                    }
                                    compact
                                    size="tiny"
                                    color="youtube"
                                  >
                                    Remove
                                  </Button>
                                  <Button
                                    compact
                                    size="tiny"
                                    primary
                                    disabled={cond?.first}
                                    onClick={() =>
                                      this.handleMoveCondition(cond.idx, 'up')
                                    }
                                  >
                                    <Button.Content>
                                      <Icon
                                        name={upSVG}
                                        size="10px"
                                        title={this.props.intl.formatMessage(
                                          messages.moveUp,
                                        )}
                                      />
                                    </Button.Content>
                                  </Button>
                                  <Button
                                    compact
                                    size="tiny"
                                    primary
                                    disabled={cond?.last}
                                    onClick={() =>
                                      this.handleMoveCondition(cond.idx, 'down')
                                    }
                                  >
                                    <Button.Content>
                                      <Icon
                                        name={downSVG}
                                        size="10px"
                                        title={this.props.intl.formatMessage(
                                          messages.moveDown,
                                        )}
                                      />
                                    </Button.Content>
                                  </Button>
                                </Card.Content>
                              </Card>
                            );
                          })}
                        </Card.Group>
                      )}
                      <Grid.Row>
                        <h4 style={{ marginTop: '15px' }}>
                          <FormattedMessage
                            id="Condition: "
                            defaultMessage="Condition: "
                          />
                        </h4>
                        <Dropdown
                          style={{ margin: '5px 0' }}
                          placeholder="Select condition"
                          fluid
                          selection
                          options={conditions_options}
                          value={this.state.selConditionToAdd}
                          onChange={(e, { value }) =>
                            this.setState({ selConditionToAdd: value })
                          }
                        />
                        <Button
                          compact
                          onClick={this.openConditionModal}
                          primary
                        >
                          <FormattedMessage id="Add" defaultMessage="Add" />
                        </Button>
                      </Grid.Row>
                    </Grid.Column>
                    <Grid.Column
                      mobile={16}
                      tablet={16}
                      computer={6}
                      largeScreen={6}
                    >
                      <h4>
                        <FormattedMessage
                          id="Perform the following actions:"
                          defaultMessage="Perform the following actions:"
                        />
                      </h4>

                      {actions && actions.length > 0 && (
                        <Card.Group>
                          {actions.map((action, i) => {
                            return (
                              <Card fluid key={i}>
                                <Card.Content>
                                  <Card.Header>
                                    <h4>{action.title}</h4>
                                  </Card.Header>
                                  <Card.Description>
                                    {action.summary}
                                  </Card.Description>
                                </Card.Content>
                                <Card.Content extra>
                                  <Button
                                    onClick={() => this.openEditAction(action)}
                                    compact
                                    size="tiny"
                                    primary
                                  >
                                    Edit
                                  </Button>
                                  <Button
                                    onClick={() =>
                                      this.handleRemoveAction(action.idx)
                                    }
                                    compact
                                    size="tiny"
                                    color="youtube"
                                  >
                                    Remove
                                  </Button>
                                  <Button
                                    compact
                                    size="tiny"
                                    primary
                                    disabled={action?.first}
                                    onClick={() =>
                                      this.handleMoveAction(action.idx, 'up')
                                    }
                                  >
                                    <Button.Content>
                                      <Icon
                                        name={upSVG}
                                        size="10px"
                                        title={this.props.intl.formatMessage(
                                          messages.moveUp,
                                        )}
                                      />
                                    </Button.Content>
                                  </Button>
                                  <Button
                                    compact
                                    size="tiny"
                                    primary
                                    disabled={action?.last}
                                    onClick={() =>
                                      this.handleMoveAction(action.idx, 'down')
                                    }
                                  >
                                    <Button.Content>
                                      <Icon
                                        name={downSVG}
                                        size="10px"
                                        title={this.props.intl.formatMessage(
                                          messages.moveDown,
                                        )}
                                      />
                                    </Button.Content>
                                  </Button>
                                </Card.Content>
                              </Card>
                            );
                          })}
                        </Card.Group>
                      )}

                      <Grid.Row>
                        <h4 style={{ marginTop: '15px' }}>
                          <FormattedMessage
                            id="Action: "
                            defaultMessage="Action: "
                          />
                        </h4>
                        <Dropdown
                          style={{ margin: '5px 0' }}
                          placeholder="Select action"
                          fluid
                          selection
                          options={actions_options}
                          onChange={(e, { value }) =>
                            this.setState({ selActionToAdd: value })
                          }
                        />
                        <Button
                          compact
                          onClick={() => this.openActionModal()}
                          primary
                        >
                          <FormattedMessage id="Add" defaultMessage="Add" />
                        </Button>
                      </Grid.Row>
                    </Grid.Column>
                  </Grid.Row>
                  <Grid.Row stretched>
                    <Grid.Column>
                      <h4>
                        <FormattedMessage
                          id="Assignments"
                          defaultMessage="Assignments"
                        />
                      </h4>
                      <FormattedMessage
                        id="This rule is assigned to the following locations:"
                        defaultMessage="This rule is assigned to the following locations:"
                      />
                      {assignments.map((assignment, i) => (
                        <UniversalLink
                          key={i}
                          title={assignment.title}
                          href={getBaseUrl(assignment.url)}
                        >
                          {assignment.title}
                        </UniversalLink>
                      ))}
                    </Grid.Column>
                  </Grid.Row>
                </Grid>
              </Segment>
            </Segment.Group>
          </article>
        </Container>
        {this.state.selConditionToAdd && (
          <VariableModal
            open={this.state.openModal}
            onClose={() =>
              this.setState({ openModal: false, selConditionToAdd: '' })
            }
            onOpen={() => this.setState({ openModal: true })}
            onSave={(v) => this.handleConditionAdd(v)}
            value={this.state.selConditionToAdd}
            type="Condition"
            action="add"
          />
        )}
        {this.state.selActionToAdd && (
          <VariableModal
            open={this.state.openModal}
            onClose={() =>
              this.setState({ openModal: false, selActionToAdd: '' })
            }
            onOpen={() => this.setState({ openModal: true })}
            onSave={(v) => this.handleActionAdd(v)}
            value={this.state.selActionToAdd}
            type="Action"
            action="add"
          />
        )}
        {this.state.selConditionToEdit && this.state.conditionFormData && (
          <VariableModal
            open={this.state.openModal}
            onClose={() =>
              this.setState({
                openModal: false,
                selConditionToEdit: '',
                conditionFormData: '',
              })
            }
            onOpen={() => this.setState({ openModal: true })}
            onSave={(v) => this.handleEditCondition(v)}
            value={this.state.selConditionToEdit}
            formData={this.state.conditionFormData}
            type="Condition"
            action="edit"
          />
        )}
        {this.state.selActionToEdit && this.state.actionFormData && (
          <VariableModal
            open={this.state.openModal}
            onClose={() =>
              this.setState({
                openModal: false,
                selActionToEdit: '',
                actionFormData: '',
              })
            }
            onOpen={() => this.setState({ openModal: true })}
            onSave={this.handleEditAction}
            value={this.state.selActionToEdit}
            formData={this.state.actionFormData}
            type="Action"
            action="edit"
          />
        )}
        {this.state.isClient &&
          createPortal(
            <Toolbar
              pathname={this.props.pathname}
              hideDefaultViewButtons
              inner={
                <Link className="item" to="#" onClick={() => this.onCancel()}>
                  <Icon
                    name={backSVG}
                    className="contents circled"
                    size="30px"
                    title={this.props.intl.formatMessage(messages.back)}
                  />
                </Link>
              }
            />,
            document.getElementById('toolbar'),
          )}
      </div>
    );
  }
}

export default compose(
  injectIntl,
  connect(
    (state, props) => ({
      pathname: props.location.pathname,
      rule: state.controlpanelrule,
    }),
    {
      getControlPanelRule,
      removeCondition,
      addCondition,
      editCondition,
      getCondition,
      getAction,
      removeAction,
      addAction,
      editAction,
      moveRuleCondition,
      moveRuleAction,
    },
  ),
)(ConfigureRule);
