// 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 PropTypes from 'prop-types';
import React, { Component } from 'react';
import { Button } from 'react-bootstrap';
import ReactSelect from 'react-select';
import '../../../../../assets/js/plugins/prettify';
import app from '../../../../app';
import FauxtonAPI from '../../../../core/api';
import ReactComponents from '../../../components/react-components';

const PaddedBorderedBox = ReactComponents.PaddedBorderedBox;
const CodeEditorPanel = ReactComponents.CodeEditorPanel;
const LoadLines = ReactComponents.LoadLines;
const getDocUrl = app.helpers.getDocUrl;

export default class MangoIndexEditor extends Component {

  constructor(props) {
    super(props);
    this.state = {
      partitionedSelected: true
    };
    this.onTemplateSelected = this.onTemplateSelected.bind(this);
    this.onTogglePartitioned = this.onTogglePartitioned.bind(this);
    this.saveIndex = this.saveIndex.bind(this);
  }

  componentDidMount() {
    prettyPrint();
    this.props.loadIndexTemplates();
    this.props.clearResults();
    this.props.loadIndexList({
      fetchParams: { ...this.props.fetchParams, skip: 0 }
    });
  }

  componentDidUpdate(prevProps) {
    prettyPrint();
    if (prevProps.templates != this.props.templates) {
      // Explicitly set value because updating 'CodeEditorPanel.defaultCode' won't change the editor once it's already loaded.
      this.setEditorValue(this.props.templates[0].value);
    }
  }

  setEditorValue(newValue = '') {
    if (this.codeEditor) {
      return this.codeEditor.getEditor().setValue(newValue);
    }
  }

  getEditorValue() {
    return this.codeEditor.getValue();
  }

  editorHasErrors() {
    return this.codeEditor.getEditor().hasErrors();
  }

  onTemplateSelected(selectedItem) {
    this.setEditorValue(selectedItem.value);
  }

  onTogglePartitioned() {
    this.setState({partitionedSelected: !this.state.partitionedSelected});
  }

  partitionedCheckobx() {
    if (!this.props.isDbPartitioned) {
      return null;
    }
    return (
      <label>
        <input
          id="js-partitioned-index"
          type="checkbox"
          checked={this.state.partitionedSelected}
          onChange={this.onTogglePartitioned}
          style={{margin: '0px 10px 0px 0px'}} />
        Partitioned
      </label>
    );
  }

  editor() {
    const encodedPartKey = this.props.partitionKey ? encodeURIComponent(this.props.partitionKey) : '';
    const editQueryURL = '#' + FauxtonAPI.urls('mango', 'query-app', encodeURIComponent(this.props.databaseName), encodedPartKey);
    return (
      <div className="mango-editor-wrapper">
        <form className="form-horizontal" onSubmit={this.saveIndex}>
          <div className="padded-box">
            <ReactSelect
              className="mango-select"
              options={this.props.templates}
              ref={node => this.templates = node}
              placeholder="Examples"
              searchable={false}
              clearable={false}
              autosize={false}
              onChange={this.onTemplateSelected}
            />
          </div>
          <PaddedBorderedBox>
            <CodeEditorPanel
              id="query-field"
              ref={node => this.codeEditor = node}
              title="Index"
              docLink={getDocUrl('MANGO_INDEX')}
              defaultCode={this.props.queryIndexCode}
              setHeightToLineCount={false}
              className="mango-code-editor"/>
            {this.partitionedCheckobx()}
          </PaddedBorderedBox>
          <div className="padded-box">
            <div className="actions-panel">
              <Button variant="cf-primary" className="btn-space" id="create-index-btn" onClick={this.saveIndex}>
              Create Index
              </Button>
              <div className="right-side-actions">
                <Button variant="cf-secondary" className="edit-link" href={editQueryURL}>Edit Query</Button>
              </div>
            </div>
          </div>
        </form>
      </div>
    );
  }

  render() {
    if (this.props.isLoading) {
      return <LoadLines />;
    }
    return this.editor();
  }

  saveIndex(event) {
    event.preventDefault();

    const showInvalidCodeMsg = () => {
      FauxtonAPI.addNotification({
        msg: 'Please fix the Javascript errors and try again.',
        type: 'error',
        clear: true
      });
    };
    if (this.editorHasErrors()) {
      showInvalidCodeMsg();
      return;
    }

    let indexCode = this.getEditorValue();
    if (this.props.isDbPartitioned) {
      // Set the partitioned property if not yet set
      try {
        const json = JSON.parse(indexCode);
        if (json.partitioned !== true && json.partitioned !== false) {
          json.partitioned = this.state.partitionedSelected;
        }
        indexCode = JSON.stringify(json);
      } catch (err) {
        showInvalidCodeMsg();
      }
    }

    this.props.saveIndex({
      databaseName: this.props.databaseName,
      indexCode: indexCode,
      fetchParams: this.props.fetchParams
    });
  }
}

MangoIndexEditor.propTypes = {
  isLoading: PropTypes.bool.isRequired,
  databaseName: PropTypes.string.isRequired,
  isDbPartitioned: PropTypes.bool.isRequired,
  saveIndex: PropTypes.func.isRequired,
  queryIndexCode: PropTypes.string.isRequired,
  partitionKey: PropTypes.string,
  loadIndexTemplates: PropTypes.func.isRequired,
  clearResults: PropTypes.func.isRequired,
  loadIndexList: PropTypes.func.isRequired
};

MangoIndexEditor.defaultProps = {
  isLoading: true,
  isDbPartitioned: false
};
