import { Spin } from 'antd';
import React from 'react';
import intl from 'react-intl-universal';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { FormInstance } from 'antd/lib/form';
import { Chart } from '@antv/g2';
import dayjs from 'dayjs';
import Panel from './Panel';
import {
  CARD_POLLING_INTERVAL,
  DETAIL_DEFAULT_RANGE,
  NEED_ADD_SUM_QUERYS,
  getBaseLineByUnit,
  getDataByType,
  getDefaultTimeRange,
  getMaxNum,
  getProperTickInterval,
} from '@/utils/dashboard';
import { IDispatch, IRootState } from '@/store';
import { VALUE_TYPE } from '@/utils/promQL';
import { SERVICE_QUERY_PERIOD } from '@/utils/service';
import { IStatRangeItem } from '@/utils/interface';
import ServiceHeader from '@/components/Service/ServiceHeader';

import LineChart from '@/components/Charts/LineChart';
import { configDetailChart, updateDetailChart } from '@/utils/chart/chart';
import Icon from '@/components/Icon';
import Modal from '@/components/Modal';
import BaseLineEdit from '@/components/BaseLineEdit';

import './index.less';

interface IState {
  serviceType: string;
  metricsValueType: VALUE_TYPE;
  instanceList: string[];
  data: IStatRangeItem[];
  maxNum: number;
  totalData: IStatRangeItem[];
  baseLine: number | undefined;
  interval: number;
  instance: string;
  metricSpace: string;
  metric: string;
  metricFunction: string;
  period: number;
  timeRange: dayjs.Dayjs[];
}

const mapDispatch = (dispatch: IDispatch) => ({
  asyncGetStatus: dispatch.service.asyncGetStatus,
  asyncGetMetricsData: dispatch.service.asyncGetMetricsData,
  asyncGetMetricsSumData: dispatch.service.asyncGetMetricsSumData,
  asyncUpdateBaseLine: (key, value) =>
    dispatch.machine.update({
      [key]: value,
    }),
});

const mapState = (state: IRootState) => ({
  loading: state.loading.models.service,
  aliasConfig: state.app.aliasConfig,
  serviceMetric: state.serviceMetric,
});

interface IProps
  extends ReturnType<typeof mapDispatch>,
  ReturnType<typeof mapState>,
  RouteComponentProps {}

class ServiceDetail extends React.Component<IProps, IState> {
  chartInstance: Chart;

  pollingTimer: any;

  modalHandler;

  formRef = React.createRef<FormInstance>();

  constructor(props: IProps) {
    super(props);
    const {
      location: { pathname },
    } = this.props;
    const regx = /(\w+)-metrics/g;
    const match = regx.exec(pathname);
    let serviceType = '';
    if (match) {
      serviceType = match[1] || 'graph';
    }
    this.state = {
      serviceType,
      metricsValueType: VALUE_TYPE.number,
      data: [],
      maxNum: 0,
      totalData: [],
      instanceList: [],
      baseLine: undefined,
      interval: DETAIL_DEFAULT_RANGE,
      instance: 'all',
      metricSpace: '',
      metric: '',
      metricFunction: '',
      period: SERVICE_QUERY_PERIOD,
      timeRange: getDefaultTimeRange(),
    };
  }

  componentDidMount() {
    const { serviceMetric } = this.props;
    const { serviceType } = this.state;
    if (serviceMetric[`${serviceType}d`].length > 0) {
      this.setState(
        {
          metric: serviceMetric[`${serviceType}d`][0]?.metric,
          metricFunction:
            serviceMetric[`${serviceType}d`][0]?.metricType?.[0].value,
          metricsValueType: serviceMetric[`${serviceType}d`][0]?.valueType,
        },
        this.pollingData,
      );
    }
  }

  /* eslint-disable-next-line */
    UNSAFE_componentWillReceiveProps(nextProps) {
    const { serviceMetric } = this.props;
    const { serviceType } = this.state;
    if (
      nextProps.serviceMetric[`${serviceType}d`] !==
      serviceMetric[`${serviceType}d`]
    ) {
      this.setState(
        {
          metric: nextProps.serviceMetric[`${serviceType}d`][0]?.metric,
          metricFunction:
            nextProps.serviceMetric[`${serviceType}d`][0]?.metricType?.[0]
              .value,
          metricsValueType:
            nextProps.serviceMetric[`${serviceType}d`][0]?.valueType,
        },
        this.pollingData,
      );
    }
  }

  componentWillUnmount() {
    this.clearPolling();
  }

  pollingData = async () => {
    await this.asyncGetMetricsData();
    this.pollingTimer = setTimeout(this.pollingData, CARD_POLLING_INTERVAL);
  };

  clearPolling = () => {
    if (this.pollingTimer) {
      clearTimeout(this.pollingTimer);
    }
  };

  resetPollingData = () => {
    this.clearPolling();
    this.pollingData();
  };

  asyncGetMetricsData = async () => {
    const { timeRange, metric, metricFunction, period } = this.state;
    const [startTime, endTime] = timeRange as any;
    let data = await this.props.asyncGetMetricsData({
      query: metricFunction + period,
      start: startTime,
      end: endTime,
    });
    if (NEED_ADD_SUM_QUERYS.includes(metric)) {
      const totalData = await this.props.asyncGetMetricsSumData({
        query: metricFunction + period,
        start: startTime,
        end: endTime,
      });
      data = data.concat(totalData);
    }
    const instanceList = data.map(item => item.metric.instanceName);
    this.setState({
      data,
      instanceList,
    });
    this.updateChart();
  };

  updateChart = () => {
    const { timeRange, instance, serviceType, data } = this.state;
    const { aliasConfig } = this.props;
    const [startTime, endTime] = timeRange as any;
    const _data = getDataByType({
      data,
      type: instance,
      name: 'instanceName',
      aliasConfig,
    });
    this.setState({
      maxNum: getMaxNum(_data),
    });
    updateDetailChart(this.chartInstance, {
      type: serviceType,
      tickInterval: getProperTickInterval(endTime - startTime),
    }).changeData(_data);
  };

  renderChart = (chartInstance: Chart) => {
    const { timeRange, metricsValueType } = this.state;
    const [startTime, endTime] = timeRange as any;
    this.chartInstance = chartInstance;
    configDetailChart(chartInstance, {
      tickInterval: getProperTickInterval(endTime - startTime),
      valueType: metricsValueType,
    });
  };

  handleServiceTypeChange = serviceType => {
    this.setState(
      {
        serviceType,
      },
      this.pollingData,
    );
  };

  handleMetricsValueTypeChange = metricsValueType => {
    this.setState({
      metricsValueType,
    });
  };

  handleIntervalChange = interval => {
    this.setState(
      {
        timeRange: getDefaultTimeRange(interval),
      },
      this.asyncGetMetricsData,
    );
  };

  handleConfigUpdate = changedValues => {
    const { serviceMetric } = this.props;
    const { serviceType } = this.state;
    if (changedValues.metric) {
      const selectedMetrics = serviceMetric[`${serviceType}d`].filter(
        item => item.metric === changedValues.metric,
      )[0];
      this.setState(
        {
          metric: changedValues.metric,
          metricsValueType: selectedMetrics.valueType,
          metricFunction: selectedMetrics.metricType[0].value,
          baseLine: undefined,
        },
        this.resetPollingData,
      );
    } else {
      this.setState(changedValues, this.resetPollingData);
    }
  };

  handleBaseLineEdit = () => {
    if (this.modalHandler) {
      this.modalHandler.show();
    }
  };

  handleClose = () => {
    if (this.modalHandler) {
      this.modalHandler.hide();
    }
  };

  handleBaseLineChange = value => {
    const { baseLine, unit } = value;
    const { metricsValueType } = this.state;
    this.setState(
      {
        baseLine: getBaseLineByUnit({
          baseLine,
          unit,
          valueType: metricsValueType,
        }),
      },
      this.handleClose,
    );
  };

  render() {
    const {
      metricsValueType,
      interval,
      instance,
      metric,
      maxNum,
      metricSpace,
      metricFunction,
      period,
      timeRange,
      serviceType,
      baseLine,
      instanceList,
    } = this.state;
    const { loading } = this.props;
    const defaultFormParams = {
      interval,
      instance,
      metric,
      space: metricSpace,
      metricFunction,
      period,
      timeRange,
    };
    return (
      <div className="service-metrics">
        <ServiceHeader
          title={`${serviceType} ${intl.get('common.metric')}`}
          icon={`#iconnav-${serviceType}`}
        />
        <div className="container">
          <Panel
            instanceList={instanceList}
            serviceType={serviceType}
            defaultFormParams={defaultFormParams}
            onTimeChange={this.handleIntervalChange}
            onServiceTypeChange={this.handleServiceTypeChange}
            onMetricsValueTypeChange={this.handleMetricsValueTypeChange}
            onConfigUpdate={this.handleConfigUpdate}
          />
          <div
            className="btn-icon-with-desc blue"
            onClick={this.handleBaseLineEdit}
          >
            <Icon icon="#iconSetup" />
            <span>{intl.get('common.baseLine')}</span>
          </div>
          <Spin spinning={!!loading} wrapperClassName="nebula-chart">
            <LineChart
              yAxisMaximum={maxNum}
              baseLine={baseLine}
              renderChart={this.renderChart}
              options={{ padding: [20, 20, 60, 50] }}
            />
          </Spin>
          <Modal
            title="empty"
            className="service-modal"
            width="550px"
            handlerRef={handler => (this.modalHandler = handler)}
            footer={null}
          >
            <BaseLineEdit
              valueType={metricsValueType}
              baseLine={baseLine || 0}
              onClose={this.handleClose}
              onBaseLineChange={this.handleBaseLineChange}
            />
          </Modal>
        </div>
      </div>
    );
  }
}
export default connect(mapState, mapDispatch)(withRouter(ServiceDetail));