import { registerComponent, Components, getCollection, Utils } from 'meteor/vulcan:lib';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import withCurrentUser from '../containers/withCurrentUser.js';
import withList from '../containers/withList.js';
import { FormattedMessage, intlShape } from 'meteor/vulcan:i18n';
import { getFieldValue } from './Card.jsx';

/*

Datatable Component

*/

// see: http://stackoverflow.com/questions/1909441/jquery-keyup-delay
const delay = (function(){
  var timer = 0;
  return function(callback, ms){
    clearTimeout (timer);
    timer = setTimeout(callback, ms);
  };
})();

class Datatable extends PureComponent {

  constructor() {
    super();
    this.updateQuery = this.updateQuery.bind(this);
    this.state = {
      value: '',
      query: '',
      currentSort: {}
    }
  }

  toggleSort = column => {
    let currentSort;
    if (!this.state.currentSort[column]) {
      currentSort = { [column] : 1 };
    } else if (this.state.currentSort[column] === 1) {
      currentSort = { [column] : -1 };
    } else {
      currentSort = {};
    }
    this.setState({ currentSort });
  }

  updateQuery(e) {
    e.persist()
    e.preventDefault();
    this.setState({
      value: e.target.value
    });
    delay(() => {
      this.setState({
        query: e.target.value
      });
    }, 700 );
  }

  render() {

    if (this.props.data) { // static JSON datatable

      return <Components.DatatableContents {...this.props} results={this.props.data}/>;
            
    } else { // dynamic datatable with data loading
      
      const collection = this.props.collection || getCollection(this.props.collectionName);
      const options = {
        collection,
        ...this.props.options
      }

      const DatatableWithList = withList(options)(Components.DatatableContents);

      const canInsert = collection.options && collection.options.mutations && collection.options.mutations.new && collection.options.mutations.new.check(this.props.currentUser);

      return (
        <div className={`datatable datatable-${collection.options.collectionName}`}>
          <Components.DatatableAbove {...this.props} collection={collection} canInsert={canInsert} value={this.state.value} updateQuery={this.updateQuery} />
          <DatatableWithList {...this.props} collection={collection} terms={{query: this.state.query, orderBy: this.state.currentSort }} currentUser={this.props.currentUser} toggleSort={this.toggleSort} currentSort={this.state.currentSort}/>
        </div>
      )
    }
  }
}

Datatable.propTypes = {
  collection: PropTypes.object,
  columns: PropTypes.array,
  data: PropTypes.array,
  options: PropTypes.object,
  showEdit: PropTypes.bool,
  showNew: PropTypes.bool,
  showSearch: PropTypes.bool,
  newFormOptions: PropTypes.object,
  editFormOptions: PropTypes.object,
  emptyState: PropTypes.object,
}

Datatable.defaultProps = {
  showNew: true,
  showEdit: true,
  showSearch: true,
}
registerComponent('Datatable', Datatable, withCurrentUser);


/*

DatatableAbove Component

*/
const DatatableAbove = (props) => {
  const { collection, currentUser, showSearch, showNew, canInsert, value, updateQuery, options, newFormOptions } = props;

  return (
    <div className="datatable-above">
      {showSearch && <input className="datatable-search form-control" placeholder="Search…" type="text" name="datatableSearchQuery" value={value} onChange={updateQuery} />}
      {showNew && canInsert && <Components.NewButton collection={collection} currentUser={currentUser} mutationFragmentName={options && options.fragmentName} {...newFormOptions}/>}
    </div>
  )
}
registerComponent('DatatableAbove', DatatableAbove);
  
/*

DatatableHeader Component

*/
const DatatableHeader = ({ collection, column, toggleSort, currentSort }, { intl }) => {

  const columnName = typeof column === 'string' ? column : column.label || column.name;
  
  if (collection) {
    const schema = collection.simpleSchema()._schema;

    /*

    use either:

    1. the column name translation
    2. the column name label in the schema (if the column name matches a schema field)
    3. the raw column name.

    */
    const defaultMessage = schema[columnName] ? schema[columnName].label : Utils.camelToSpaces(columnName);
    const formattedLabel = intl.formatMessage({ id: `${collection._name}.${columnName}`, defaultMessage });

    // if sortable is a string, use it as the name of the property to sort by. If it's just `true`, use column.name
    const sortPropertyName = typeof column.sortable === 'string' ? column.sortable : column.name;
    return column.sortable ? <Components.DatatableSorter name={sortPropertyName} label={formattedLabel} toggleSort={toggleSort} currentSort={currentSort} sortable={column.sortable}/> : <th>{formattedLabel}</th>;

  } else {

    const formattedLabel = intl.formatMessage({ id: columnName, defaultMessage: columnName });
    return <th className={`datatable-th-${columnName.toLowerCase().replace(/\s/g,'-')}`}>{formattedLabel}</th>;

  }
}

DatatableHeader.contextTypes = {
  intl: intlShape
};

registerComponent('DatatableHeader', DatatableHeader);

const SortNone = () =>
  <svg width='16' height='16' viewBox='0 0 438 438' fill='none' xmlns='http://www.w3.org/2000/svg'>
    <path d='M25.7368 247.243H280.263C303.149 247.243 314.592 274.958 298.444 291.116L171.18 418.456C161.128 428.515 144.872 428.515 134.926 418.456L7.55631 291.116C-8.59221 274.958 2.85078 247.243 25.7368 247.243ZM298.444 134.884L171.18 7.54408C161.128 -2.51469 144.872 -2.51469 134.926 7.54408L7.55631 134.884C-8.59221 151.042 2.85078 178.757 25.7368 178.757H280.263C303.149 178.757 314.592 151.042 298.444 134.884Z' transform='translate(66 6)' fill='#000' fillOpacity='0.2' />
  </svg>

const SortDesc = () =>
  <svg width="16" height="16" viewBox="0 0 438 438" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M25.7368 0H280.263C303.149 0 314.592 27.7151 298.444 43.8734L171.18 171.213C161.128 181.272 144.872 181.272 134.926 171.213L7.55631 43.8734C-8.59221 27.7151 2.85078 0 25.7368 0Z" transform="translate(66 253.243)" fill="black" fillOpacity="0.7"/>
    <path d="M171.18 7.54408L298.444 134.884C314.592 151.042 303.149 178.757 280.263 178.757H25.7368C2.85078 178.757 -8.59221 151.042 7.55631 134.884L134.926 7.54408C144.872 -2.51469 161.128 -2.51469 171.18 7.54408Z" transform="translate(66 6)" fill="black" fillOpacity="0.2"/>
  </svg>

const SortAsc = () =>
  <svg width="16" height="16" viewBox="0 0 438 438" fill="none" xmlns="http://www.w3.org/2000/svg">
    <path d="M298.444 134.884L171.18 7.54408C161.128 -2.51469 144.872 -2.51469 134.926 7.54408L7.55631 134.884C-8.59221 151.042 2.85078 178.757 25.7368 178.757H280.263C303.149 178.757 314.592 151.042 298.444 134.884Z" transform="translate(66 6)" fill="black" fillOpacity="0.7"/>
    <path d="M280.263 0H25.7368C2.85078 0 -8.59221 27.7151 7.55631 43.8734L134.926 171.213C144.872 181.272 161.128 181.272 171.18 171.213L298.444 43.8734C314.592 27.7151 303.149 0 280.263 0Z" transform="translate(66 253.243)" fill="black" fillOpacity="0.2"/>
  </svg>

const DatatableSorter = ({ name, label, toggleSort, currentSort }) => 

  <th>
    <div className="datatable-sorter" onClick={() => {toggleSort(name)}}>
      <span className="datatable-sorter-label">{label}</span>
      <span className="sort-icon">
        {!currentSort[name] ? (
          <SortNone/> 
        ) : currentSort[name] === 1 ? (
          <SortDesc/> 
        ) : (
          <SortAsc/>
        )
      }
      </span>
    </div>
  </th>

registerComponent('DatatableSorter', DatatableSorter);

/*

DatatableContents Component

*/

const DatatableContents = (props) => {

  const {collection, columns, results, loading, loadMore, count, totalCount, networkStatus, showEdit, currentUser, emptyState, toggleSort, currentSort } = props;

  if (loading) {
    return <div className="datatable-list datatable-list-loading"><Components.Loading /></div>;
  } else if (!results || !results.length) {
    return emptyState || null;
  }

  const isLoadingMore = networkStatus === 2;
  const hasMore = totalCount > results.length;

  return (
    <div className="datatable-list">
        <table className="table">
          <thead>
            <tr>
              {_.sortBy(columns, column => column.order).map((column, index) => <Components.DatatableHeader key={index} collection={collection} column={column} toggleSort={toggleSort} currentSort={currentSort} />)}
              {showEdit ? <th><FormattedMessage id="datatable.edit"/></th> : null}
            </tr>
          </thead>
          <tbody>
            {results.map((document, index) => <Components.DatatableRow {...props} collection={collection} columns={columns} document={document} key={index} showEdit={showEdit} currentUser={currentUser}/>)}
          </tbody>
        </table>
        {hasMore &&
          <div className="datatable-list-load-more">
            {isLoadingMore ?
              <Components.Loading/> :
              <Components.Button variant="primary" onClick={e => {e.preventDefault(); loadMore();}}>Load More ({count}/{totalCount})</Components.Button>
            }
          </div>
        }
      </div>
  )
}
registerComponent('DatatableContents', DatatableContents);

/*

DatatableRow Component

*/
const DatatableRow = (props, { intl }) => {

  const { collection, columns, document, showEdit, currentUser, options, editFormOptions, rowClass } = props;
  const canEdit = collection && collection.options && collection.options.mutations && collection.options.mutations.edit && collection.options.mutations.edit.check(currentUser, document);

  const row = typeof rowClass === 'function' ? rowClass(document) : rowClass || '';
  const modalProps = { title: <code>{document._id}</code> };

  return (
  <tr className={`datatable-item ${row}`}>

    {_.sortBy(columns, column => column.order).map((column, index) => <Components.DatatableCell key={index} column={column} document={document} currentUser={currentUser} />)}

    {showEdit && canEdit ?
      <td>
        <Components.EditButton collection={collection} documentId={document._id} currentUser={currentUser} mutationFragmentName={options && options.fragmentName} modalProps={modalProps} {...editFormOptions}/>
      </td>
    : null}

  </tr>
  )
}
registerComponent('DatatableRow', DatatableRow);

DatatableRow.contextTypes = {
  intl: intlShape
};

/*

DatatableCell Component

*/
const DatatableCell = ({ column, document, currentUser }) => {
  const Component = column.component || column.componentName && Components[column.componentName] || Components.DatatableDefaultCell;
  const columnName = column.name || column;
  return (
    <td className={`datatable-item-${columnName.toLowerCase().replace(/\s/g,'-')}`}><Component column={column} document={document} currentUser={currentUser} /></td>
  )
}
registerComponent('DatatableCell', DatatableCell);

/*

DatatableDefaultCell Component

*/
const DatatableDefaultCell = ({ column, document }) =>
  <div>{typeof column === 'string' ? getFieldValue(document[column]) : getFieldValue(document[column.name])}</div>

registerComponent('DatatableDefaultCell', DatatableDefaultCell);
