import React from 'react';
import PropTypes from 'prop-types';
import { Responsive, WidthProvider } from 'react-grid-layout';

import GridCell from './GridCell';
import { getExploreUrl } from '../../explore/exploreUtils';

require('react-grid-layout/css/styles.css');
require('react-resizable/css/styles.css');

const ResponsiveReactGridLayout = WidthProvider(Responsive);

const propTypes = {
  dashboard: PropTypes.object.isRequired,
  datasources: PropTypes.object,
  charts: PropTypes.object.isRequired,
  filters: PropTypes.object,
  timeout: PropTypes.number,
  onChange: PropTypes.func,
  getFormDataExtra: PropTypes.func,
  fetchSlice: PropTypes.func,
  saveSlice: PropTypes.func,
  removeSlice: PropTypes.func,
  removeChart: PropTypes.func,
  updateDashboardLayout: PropTypes.func,
  toggleExpandSlice: PropTypes.func,
  addFilter: PropTypes.func,
  getFilters: PropTypes.func,
  clearFilter: PropTypes.func,
  removeFilter: PropTypes.func,
  editMode: PropTypes.bool.isRequired,
};

const defaultProps = {
  onChange: () => ({}),
  getFormDataExtra: () => ({}),
  fetchSlice: () => ({}),
  saveSlice: () => ({}),
  removeSlice: () => ({}),
  removeChart: () => ({}),
  updateDashboardLayout: () => ({}),
  toggleExpandSlice: () => ({}),
  addFilter: () => ({}),
  getFilters: () => ({}),
  clearFilter: () => ({}),
  removeFilter: () => ({}),
};

class GridLayout extends React.Component {
  constructor(props) {
    super(props);

    this.onResizeStop = this.onResizeStop.bind(this);
    this.onDragStop = this.onDragStop.bind(this);
    this.forceRefresh = this.forceRefresh.bind(this);
    this.removeSlice = this.removeSlice.bind(this);
    this.updateSliceName = this.props.dashboard.dash_edit_perm ?
      this.updateSliceName.bind(this) : null;
  }

  onResizeStop(layout) {
    this.props.updateDashboardLayout(layout);
    this.props.onChange();
  }

  onDragStop(layout) {
    this.props.updateDashboardLayout(layout);
    this.props.onChange();
  }

  getWidgetId(slice) {
    return 'widget_' + slice.slice_id;
  }

  getWidgetHeight(slice) {
    const widgetId = this.getWidgetId(slice);
    if (!widgetId || !this.refs[widgetId]) {
      return 400;
    }
    return this.refs[widgetId].offsetHeight;
  }

  getWidgetWidth(slice) {
    const widgetId = this.getWidgetId(slice);
    if (!widgetId || !this.refs[widgetId]) {
      return 400;
    }
    return this.refs[widgetId].offsetWidth;
  }

  findSliceIndexById(sliceId) {
    return this.props.dashboard.slices
      .map(slice => (slice.slice_id)).indexOf(sliceId);
  }

  forceRefresh(sliceId) {
    return this.props.fetchSlice(this.props.charts['slice_' + sliceId], true);
  }

  removeSlice(slice) {
    if (!slice) {
      return;
    }

    // remove slice dashbaord and charts
    this.props.removeSlice(slice);
    this.props.removeChart(this.props.charts['slice_' + slice.slice_id].chartKey);
    this.props.onChange();
  }

  updateSliceName(sliceId, sliceName) {
    const index = this.findSliceIndexById(sliceId);
    if (index === -1) {
      return;
    }

    const currentSlice = this.props.dashboard.slices[index];
    if (currentSlice.slice_name === sliceName) {
      return;
    }

    this.props.saveSlice(currentSlice, sliceName);
  }

  isExpanded(slice) {
    return this.props.dashboard.metadata.expanded_slices &&
      this.props.dashboard.metadata.expanded_slices[slice.slice_id];
  }

  render() {
    const cells = this.props.dashboard.slices.map((slice) => {
      const chartKey = `slice_${slice.slice_id}`;
      const currentChart = this.props.charts[chartKey];
      const queryResponse = currentChart.queryResponse || {};
      return (
        <div
          id={'slice_' + slice.slice_id}
          key={slice.slice_id}
          data-slice-id={slice.slice_id}
          className={`widget ${slice.form_data.viz_type}`}
          ref={this.getWidgetId(slice)}
        >
          <GridCell
            slice={slice}
            chartKey={chartKey}
            datasource={this.props.datasources[slice.form_data.datasource]}
            filters={this.props.filters}
            formData={this.props.getFormDataExtra(slice)}
            timeout={this.props.timeout}
            widgetHeight={this.getWidgetHeight(slice)}
            widgetWidth={this.getWidgetWidth(slice)}
            exploreChartUrl={getExploreUrl(this.props.getFormDataExtra(slice))}
            exportCSVUrl={getExploreUrl(this.props.getFormDataExtra(slice), 'csv')}
            isExpanded={!!this.isExpanded(slice)}
            isLoading={currentChart.chartStatus === 'loading'}
            isCached={queryResponse.is_cached}
            cachedDttm={queryResponse.cached_dttm}
            toggleExpandSlice={this.props.toggleExpandSlice}
            forceRefresh={this.forceRefresh}
            removeSlice={this.removeSlice}
            updateSliceName={this.updateSliceName}
            addFilter={this.props.addFilter}
            getFilters={this.props.getFilters}
            clearFilter={this.props.clearFilter}
            removeFilter={this.props.removeFilter}
            editMode={this.props.editMode}
            annotationQuery={currentChart.annotationQuery}
            annotationError={currentChart.annotationError}
          />
        </div>);
    });

    return (
      <ResponsiveReactGridLayout
        className="layout"
        layouts={{ lg: this.props.dashboard.layout }}
        onResizeStop={this.onResizeStop}
        onDragStop={this.onDragStop}
        cols={{ lg: 12, md: 12, sm: 10, xs: 8, xxs: 6 }}
        rowHeight={100}
        autoSize
        margin={[20, 20]}
        useCSSTransforms
        draggableHandle=".drag"
      >
        {cells}
      </ResponsiveReactGridLayout>
    );
  }
}

GridLayout.propTypes = propTypes;
GridLayout.defaultProps = defaultProps;

export default GridLayout;
