import * as React from 'react';
import {
  ComponentModeWindow,
  MmuiCommonComponent,
  MmuiProps,
  MmuiState,
  COMPONENT_MODE_INITIAL,
  COMPONENT_MODE_EMPTY,
  COMPONENT_MODE_ERROR,
  COMPONENT_MODE_LOADING,
  COMPONENT_MODE_OK,
} from './common';

import { buildChart } from 'mmviz';

export type ChartUpdateViewCallback = (a: any) => void;

export interface MmuiChartProps extends MmuiProps {
  chartId: string; // html element id of the chart
  chartConfig: any; // chart configuration, including selector, xScale, yScale, axis config, etc, could be different for each type of chart
  dataModel: any; // map data to keyMap, valueMap, detailsMap, could be different for each type of chart
  chartUpdateViewCallback: ChartUpdateViewCallback; // update chart view with resize
  payload?: any; // received from the server, includes data, whether data hasError, isInvalidated, etc
  reportIssueUrl?: string; // url link to report issue when something goes wrong
}

/**
 * Chart Component for rendering different types of charts (bar chart, line chart, etc.)
 * The data payload is passed in the props. Either this.props.payload or this.props.store.data (store)
 * Props values can be passed in when calling ReactDOM to render the chart component
 * MmuiChartComponent will be overlaid by ComponentModeWindow when mode is not OK (loading, error, empty)
 */
export class MmuiChartComponent<
  P extends MmuiChartProps,
  S extends MmuiState
> extends MmuiCommonComponent<P, S> {
  constructor(props: MmuiChartProps) {
    super(props);
  }

  /**
   * Extract the dataArray portion of the payload received from the server.
   * @param payload
   */
  extractDataArray(payload) {
    let dataArray = [];
    if (payload && payload.data) {
      dataArray = payload.data;
    }

    return dataArray;
  }

  /**
   * Get Component mode based on data payload
   */
  getComponentMode(payload) {
    let mode = COMPONENT_MODE_INITIAL,
      dataArray,
      hasData = false;
    if (payload) {
      if (payload.hasError) {
        mode = COMPONENT_MODE_ERROR;
      } else if (payload.isInvalidated) {
        mode = COMPONENT_MODE_LOADING;
      } else {
        dataArray = this.extractDataArray(payload);
        hasData = dataArray.length > 0;
        if (hasData) {
          mode = COMPONENT_MODE_OK;
        } else {
          mode = COMPONENT_MODE_EMPTY;
        }
      }
    }

    return mode;
  }

  componentDidMount() {
    const payload = this.getPayloadData();
    const a_la_mode = this.getComponentMode(payload);
    if (a_la_mode == COMPONENT_MODE_OK) {
      const dataArray = this.extractDataArray(payload);
      const dataModel = this.props.dataModel;
      dataModel.dataArray = dataArray;
      const chart = buildChart(dataModel, this.props.chartConfig);
      chart();
      if (this.props.chartUpdateViewCallback) {
        this.props.chartUpdateViewCallback(chart);
      }
    }
  }

  /**
   * On update to Component props or state
   */
  componentDidUpdate() {
    const payload = this.getPayloadData();
    const a_la_mode = this.getComponentMode(payload);
    if (a_la_mode == COMPONENT_MODE_OK) {
      const dataArray = this.extractDataArray(payload);
      const dataModel = this.props.dataModel;
      dataModel.dataArray = dataArray;
      const chart = buildChart(dataModel, this.props.chartConfig);
      chart();
      if (this.props.chartUpdateViewCallback) {
        this.props.chartUpdateViewCallback(chart);
      }
    }
  }

  /**
   * Render the Chart Component
   */

  render() {
    const payload = this.getPayloadData();
    const a_la_mode = this.getComponentMode(payload);
    let chartContent = null;
    if (a_la_mode == COMPONENT_MODE_OK) {
      chartContent = (
        <div className="chart-panel-body">
          <div id={this.props.chartId} className="chart"></div>
        </div>
      );
    }
    return (
      <React.Fragment>
        {chartContent}
        <ComponentModeWindow
          mode={a_la_mode}
          reportIssueUrl={this.props.reportIssueUrl}
          loadingGraphicUrl={this.loadingImage}
          hasEmptyMode={true}
          hasErrorMode={true}
        />
      </React.Fragment>
    );
  }
}
