import React, { useContext, useState, useReducer, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Highcharts from 'highcharts/highstock';
import HighchartsReact from 'highcharts-react-official';
import { Tabs, Select, Radio, Checkbox, ConfigProvider, DatePicker } from 'antd';
import { PlusCircleOutlined } from '@ant-design/icons';
import TimeRangePicker from '@wisdom-components/timerangepicker';
import BasicTable from '@wisdom-components/basictable';
import Empty from '@wisdom-components/empty';
import moment from 'moment';
import './index.less';

const { TabPane } = Tabs;
const { RangePicker } = DatePicker;
const { Option } = Select;

const UPDATE_TIME = {
  UPDATE_TIME: 'updateTime',
  UPDATE_BATCH_TIME: 'updateBatchTime',
  UPDATE_DATA_THIN: 'updateDataThin',
};

const reducer = (state, action) => {
  switch (action.type) {
    case UPDATE_TIME.UPDATE_TIME:
      return {
        ...state,
        dateRange: updateTime(action.payload),
      };
    case UPDATE_TIME.UPDATE_BATCH_TIME:
      return {
        ...state,
        dateRange: action.payload,
      };
    case 'updateIgnoreOutliers':
      return {
        ...state,
        ignoreOutliers: action.payload,
      };
    case UPDATE_TIME.UPDATE_DATA_THIN:
      const { zoom, unit } = action.payload;
      return {
        ...state,
        zoom,
        unit,
      };
    default:
      throw new Error();
  }
};

const updateTime = (key) => {
  let start = '',
    end = '';
  if (Array.isArray(key)) {
    start = moment(key[0]).format(timeFormat);
    end = moment(key[1]).format(timeFormat);
  } else {
    switch (key) {
      case 'oneHour':
        start = moment().subtract(1, 'hour').format(timeFormat);
        end = moment().format(timeFormat);
        break;
      case 'fourHour':
        start = moment().subtract(4, 'hour').format(timeFormat);
        end = moment().format(timeFormat);
        break;
      case 'twelveHours':
        start = moment().subtract(12, 'hour').format(timeFormat);
        end = moment().format(timeFormat);
        break;
      case 'roundClock':
        start = moment().subtract(24, 'hour').format(timeFormat);
        end = moment().format(timeFormat);
        break;
      case 'yesterday':
        start = moment().subtract(1, 'days').format(startFormat);
        end = moment().subtract(1, 'days').format(endFormat);
        break;
    }
  }
  return [
    {
      dateFrom: start,
      dateTo: end,
    },
  ];
};

const unique = (arr) => {
  let unique = {};
  arr.forEach((item) => {
    unique[JSON.stringify(item)] = item;
  });
  arr = Object.keys(unique).map((v) => {
    return JSON.parse(v);
  });
  return arr;
};

let chartWidth = 0; // chart width
let chartHeight = 0; // chart height

const HistoryInfo = (props) => {
  const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
  const prefixCls = getPrefixCls('history-info');

  const { title, columns, dataSource, tableProps, chartOptions, onChange } = props;

  const [activeTabKey, setActiveTabKey] = useState('curve');
  const [timeValue, setTimeValue] = useState('customer');
  const [contrastOption, setContrastOption] = useState('day');
  const [customerChecked, setCustomerChecked] = useState(props.defaultChecked || 'oneHour');
  const [customerTime, setCustomerTime] = useState(null);
  const [datePickerArr, setDatePickerArr] = useState(DataPickerArr);
  const [checkboxData, setCheckboxData] = useState(CheckboxData);
  const [dataThinKey, setDataThinKey] = useState(timeIntervalList[0].key);
  const [options, setOptions] = useState({});

  const [state, dispatch] = useReducer(reducer, initialState);

  const container = useRef(null);

  useEffect(() => {
    onChange(state);
  }, [state]);

  useEffect(() => {
    dispatch({ type: UPDATE_TIME.UPDATE_TIME, payload: props.defaultChecked });
  }, [props.defaultChecked]);

  useEffect(() => {
    setOptions({ ...handleChartOptions() });
  }, [chartOptions]);

  // 时间设置切换（自定义/同期对比）
  const onTimeSetChange = (e) => {
    setTimeValue(e.target.value);
  };

  // 选择（日/月）
  const onContrastChange = (value) => {
    setContrastOption(value);
    handleBatchTime([...datePickerArr], value);
  };

  const onCustomerRangeChange = (value) => {
    setCustomerTime(value);
    dispatch({ type: UPDATE_TIME.UPDATE_TIME, payload: value });
  };

  const onCustomerTimeChange = (key) => {
    setCustomerChecked(key);
    dispatch({ type: UPDATE_TIME.UPDATE_TIME, payload: key });
  };

  const handleBatchTime = (arr, contrastOption) => {
    let newArr = [];
    arr.forEach((child) => {
      if (child.value) {
        newArr.push({
          dateFrom: moment(child.value).startOf(contrastOption).format(startFormat),
          dateTo: moment(child.value).endOf(contrastOption).format(endFormat),
        });
      }
    });
    newArr = unique(newArr);
    dispatch({ type: UPDATE_TIME.UPDATE_BATCH_TIME, payload: newArr });
  };

  const onContrastPickerChange = (date, dateString, item) => {
    let arr = [...datePickerArr];
    arr.forEach((child) => {
      if (child.key === item.key) {
        child.value = date;
      }
    });
    handleBatchTime(arr, contrastOption);
  };

  //新增日期选择组件
  const handleAddDatePicker = () => {
    setDatePickerArr([
      ...datePickerArr,
      {
        key: datePickerArr.length + 1,
        value: '',
      },
    ]);
  };

  const onCheckboxChange = (e, key) => {
    let data = [...checkboxData];
    data.forEach((item) => {
      if (item.key === key) {
        item.checked = e.target.checked;
        if (key === 'dataThin') {
          if (e.target.checked) {
            timeIntervalList.forEach((child) => {
              if (child.key === dataThinKey) {
                dispatch({ type: item.type, payload: { zoom: dataThinKey, unit: child.unit } });
              }
            });
          } else {
            dispatch({ type: item.type, payload: { zoom: '', unit: '' } });
          }
        }
        if (key === 'ignoreOutliers') {
          dispatch({ type: item.type, payload: e.target.checked });
        }
        if (key === 'curveCenter') {
          setOptions({ ...handleChartOptions() });
        }
      }
    });
    setCheckboxData(data);
  };

  // 数据抽稀时间间隔
  const onTimeIntervalChange = (value, { unit }) => {
    let data = checkboxData.filter((item) => item.key === 'dataThin');
    if (data[0].checked) {
      dispatch({ type: UPDATE_TIME.UPDATE_DATA_THIN, payload: { zoom: value, unit: unit } });
    }
    setDataThinKey(value);
  };

  const renderCheckbox = (child) => (
    <Checkbox
      value={child.key}
      checked={child.checked}
      onChange={(e) => onCheckboxChange(e, child.key)}
    >
      {child.label}
    </Checkbox>
  );

  const renderOptions = (item) => {
    return (
      <>
        <div className={classNames(`${prefixCls}-time`)}>
          <div className={classNames(`${prefixCls}-label`)}>时间</div>
          <Radio.Group defaultValue={timeValue} onChange={onTimeSetChange}>
            <Radio.Button value="customer">自定义</Radio.Button>
            <Radio.Button value="contrast">同期对比</Radio.Button>
          </Radio.Group>
          {timeValue === 'customer' && ( // 自定义
            <>
              <TimeRangePicker
                onChange={onCustomerTimeChange}
                value={customerChecked}
                dataSource={timeList}
              />
              <RangePicker
                className={classNames(`${prefixCls}-customer`)}
                onChange={onCustomerRangeChange}
                value={customerTime}
                showTime
              />
            </>
          )}
          {timeValue === 'contrast' && ( // 同期对比
            <>
              <Select value={contrastOption} style={{ width: 60 }} onChange={onContrastChange}>
                <Option value="day">日</Option>
                <Option value="month">月</Option>
              </Select>
              {datePickerArr.map((child, index) => (
                <div key={child.key} className={classNames(`${prefixCls}-contrast-list`)}>
                  <div className={classNames(`${prefixCls}-connect`, { first: child.key === 1 })}>
                    与
                  </div>
                  <DatePicker
                    picker={contrastOption}
                    value={child.value}
                    onChange={(date, dateString) => onContrastPickerChange(date, dateString, child)}
                  />
                </div>
              ))}
              {datePickerArr.length < 5 && <PlusCircleOutlined onClick={handleAddDatePicker} />}
            </>
          )}
        </div>
        <div className={classNames(`${prefixCls}-cover`)}>
          <div className={classNames(`${prefixCls}-label`)}>曲线设置</div>
          {checkboxData.map((child) => (
            <div key={child.key}>
              {item.key === 'curve' && renderCheckbox(child)}
              {item.key === 'table' && child.key !== 'curveCenter' && renderCheckbox(child)}
            </div>
          ))}
          <Select value={dataThinKey} style={{ width: 90 }} onChange={onTimeIntervalChange}>
            {timeIntervalList.map((child) => (
              <Option key={child.key} unit={child.unit} value={child.key}>
                {child.name}
              </Option>
            ))}
          </Select>
        </div>
      </>
    );
  };

  const getSeriesType = (sensorName) => {
    return sensorName ? (sensorName.indexOf('流量') > -1 ? 'area' : 'spline') : 'spline';
  };

  // 处理图表options
  const handleChartOptions = () => {
    const { series } = chartOptions;
    let _series = [];
    let _yAxis = [];
    let uniqueUnit = [];
    series.forEach((item, index) => {
      // 处理series
      let _s = {
        name: item.name,
        type: getSeriesType(item.sensorName),
        data: item.data,
        zIndex: 1,
        tooltip: { valueSuffix: item.unit ? item.unit : '' },
        color: colors[index],
        decimalPoint: item.decimalPoint,
        navigatorOptions: {
          enabled: true,
        },
      };
      if (_s.type === 'area' || _s.type === 'areaspline') {
        _s.fillColor = {
          linearGradient: {
            x1: 0,
            y1: 0,
            x2: 0,
            y2: 1,
          },
          stops: [
            [0, Highcharts.Color(_s.color).setOpacity(0.1).get('rgba')],
            [1, '#fff'],
          ],
        };
        _s.threshold = 0;
      }

      // 处理yAxis
      if (!uniqueUnit.includes(item.unit)) {
        uniqueUnit.push(item.unit);
        let _length = uniqueUnit.length - 1;
        let _y = {
          title: {
            text: item.unit,
            align: 'high',
            offset: 0,
            rotation: 0,
            y: -25,
            x: 0,
          },
          gridLineWidth: 1,
          gridLineDashStyle: 'dash',
          lineWidth: 1,
          tickAmount: 10,
          crosshair: true,
          floor: 0,
          num: _length,
          opposite: _length % 2 === 0,
          offset: Math.floor(_length / 2) * 40,
          style: {
            color: '',
          },
          labels: {
            style: {
              color: '',
            },
            x: -2,
          },
        };
        _yAxis.push(_y);
      }

      // 处理series
      _s.yAxis = uniqueUnit.findIndex((child) => child === item.unit);

      _series.push(_s);
    });

    Highcharts.setOptions({
      global: { timezoneOffset: -8 * 60 },
    });

    let options = { ...defaultOptions };

    if (CheckboxData[0].checked) {
      _yAxis = setYaxisMin(_yAxis, _series);
    } else {
      _yAxis = _yAxis.map((item) => ({ ...item, max: null, min: null }));
    }

    if (_yAxis.length > 0) {
      options = {
        ...defaultOptions,
        ...chartOptions,
        yAxis: _yAxis,
        series: _series,
      };
    }

    options.tooltip.formatter = function formatter() {
      let _html = `<b>${Highcharts.dateFormat(
        contrastOption === 'day' ? '%H:%M' : '%d %H:%M',
        this.x,
      )}</b><br/>`;
      this.points.forEach((item) => {
        _html += `<span style={{color: ${item.series.color}}}>${item.series.name}</span>:
                <b>${
                  item.point.y.toFixed(
                    item.series.userOptions.decimalPoint ? item.series.userOptions.decimalPoint : 2,
                  ) * 1
                }${item.series.userOptions.tooltip.valueSuffix}</b>
                <br/>`;
      });
      return _html;
    };

    if (container.current) {
      if (container.current.offsetWidth !== 0) {
        chartWidth = container.current.offsetWidth;
        chartHeight = container.current.offsetHeight;
      }
      Highcharts.setOptions({
        // 处理 chart 高度坍塌
        chart: {
          width: container.current.offsetWidth === 0 ? chartWidth : container.current.offsetWidth,
          height:
            container.current.offsetHeight === 0 ? chartHeight : container.current.offsetHeight,
        },
      });
    }

    return options;
  };

  const setYaxisMin = (y, data) => {
    let result = y.concat();

    data.forEach((val) => {
      let min = 999999999;
      let showMin = 999999999;
      let max = -999999999;
      let showMax = -999999999;
      val.data.forEach((item) => {
        if (item[1]) {
          min = Math.min(min, item[1]);
          showMin = Math.min(min, item[1]);
          max = Math.max(max, item[1]);
          showMax = Math.max(max, item[1]);
        }
      });
      let k = 0;
      let same = false;
      for (let i = 0; i < val.data.length; i++) {
        // 判断是否全为0
        if (val.data[i][1] !== 0) {
          k = 1;
        }
        // 判断是否全相等
        if (i >= 1 && val.data[i][1] !== val.data[i - 1][1]) {
          same = true;
        }
      }

      if (k === 0) {
        result[val.yAxis].min = result[val.yAxis].min
          ? Math.min(result[val.yAxis].min, -0.2)
          : -0.2;
        result[val.yAxis].max = result[val.yAxis].max ? Math.max(result[val.yAxis].max, 0.2) : 0.2;
      } else if (!same) {
        min = val.data[0][1] > 0 ? val.data[0][1] * 0.5 : val.data[0][1] * 1.5;
        max = val.data[0][1] > 0 ? val.data[0][1] * 1.5 : val.data[0][1] * 0.5;
        result[val.yAxis].min = result[val.yAxis].min
          ? Math.min(result[val.yAxis].min, showMin)
          : min;
        result[val.yAxis].max = result[val.yAxis].max ? Math.max(result[val.yAxis].max, max) : max;
      } else {
        result[val.yAxis].min = result[val.yAxis].min
          ? Math.min(result[val.yAxis].min, min)
          : showMin;
        result[val.yAxis].max = result[val.yAxis].max
          ? Math.max(result[val.yAxis].max, max)
          : showMax;
      }
    });

    return result;
  };

  return (
    <div className={classNames(prefixCls)}>
      <Tabs
        activeKey={activeTabKey}
        centered
        tabBarExtraContent={{
          left: <h3 className="tabs-extra-demo-button">{title}</h3>,
        }}
        onChange={(key) => setActiveTabKey(key)}
      >
        {TabPaneData.map((item) => (
          <TabPane tab={item.tab} key={item.key}>
            <div className={classNames(`${prefixCls}-content`)}>
              {renderOptions(item)}
              {!dataSource.length && <Empty />}
              {!!dataSource.length && (
                <div className={classNames(`${prefixCls}-wrap`)}>
                  <div className={classNames(`${prefixCls}-main`)}>
                    {item.key === 'curve' && (
                      <div className={classNames(`${prefixCls}-chart`)} ref={container}>
                        <HighchartsReact
                          immutable={true}
                          highcharts={Highcharts}
                          constructorType={'stockChart'}
                          options={options}
                          allowChartUpdate={true}
                        />
                      </div>
                    )}
                    {item.key === 'table' && (
                      <BasicTable dataSource={dataSource} columns={columns} {...tableProps} />
                    )}
                  </div>
                </div>
              )}
            </div>
          </TabPane>
        ))}
      </Tabs>
    </div>
  );
};

HistoryInfo.defaultProps = {
  title: '指标曲线',
  defaultChecked: 'oneHour',
  columns: [],
  dataSource: [],
  tableProps: {},
  chartOptions: {},
  onChange: () => {},
};

HistoryInfo.propTypes = {
  title: PropTypes.string,
  defaultChecked: PropTypes.string,
  columns: PropTypes.array,
  dataSource: PropTypes.array,
  tableProps: PropTypes.object,
  chartOptions: PropTypes.object,
  onChange: PropTypes.func,
};

export default HistoryInfo;

const startFormat = 'YYYY-MM-DD 00:00:00';
const endFormat = 'YYYY-MM-DD 23:59:59';

const timeFormat = 'YYYY-MM-DD HH:mm:ss';

const colors = [
  '#1884EC',
  '#90CE53',
  '#86E0C7',
  '#68cbd1',
  '#bb98d1',
  '#588c66',
  '#b0859e',
  '#647fac',
  '#7c6894',
  '#9c8273',
  '#838b61',
  '#437db0',
  '#9b97c4',
  '#bda589',
  '#89bd8e',
  '#cbcc75',
];

const defaultOptions = {
  chart: {
    zoomType: 'x',
    backgroundColor: 'rgba(255, 255, 255, 0.5)',
  },
  colors: colors,
  title: null,
  credits: false,
  rangeSelector: {
    enabled: false,
  },
  xAxis: [
    {
      lineWidth: 0,
      crosshair: true,
      type: 'datetime',
      gridLineDashStyle: 'dash',
      gridLineWidth: 1,
      dateTimeLabelFormats: {
        second: '%H:%M:%S',
        minute: '%H:%M',
        hour: '%H:%M',
        day: '%d',
        week: '%d',
        month: '%d',
        year: '%Y',
      },
    },
  ],
  yAxis: [],
  tooltip: {
    shared: true,
    split: false,
    valueDecimals: 3,
  },
  plotOptions: {
    series: {
      showInNavigator: true,
      connectNulls: false,
      zoneAxis: 'x',
    },
  },
  legend: {
    enabled: true,
    verticalAlign: 'top',
  },
  series: [],
  responsive: {
    rules: [
      {
        condition: {
          maxWidth: 800,
          minHeight: 500,
        },
      },
    ],
  },
};

const initialState = {
  dateRange: [],
  ignoreOutliers: false,
  isVertical: false,
  zoom: '',
  unit: '',
};

const TabPaneData = [
  {
    key: 'curve',
    tab: '曲线',
  },
  {
    key: 'table',
    tab: '表格',
  },
];

const CheckboxData = [
  {
    key: 'curveCenter',
    label: '曲线居中',
    checked: false,
  },
  {
    key: 'ignoreOutliers',
    label: '过滤异常值',
    type: 'updateIgnoreOutliers',
    checked: false,
  },
  {
    key: 'dataThin',
    label: '数据抽稀',
    type: 'updateDataThin',
    checked: false,
  },
];

const timeList = [
  {
    key: 'oneHour',
    name: '近1小时',
  },
  {
    key: 'fourHour',
    name: '近4小时',
  },
  {
    key: 'twelveHours',
    name: '近12小时',
  },
  {
    key: 'roundClock',
    name: '近24小时',
  },
  {
    key: 'yesterday',
    name: '昨天',
  },
];

const timeIntervalList = [
  {
    key: '5',
    unit: 'min',
    name: '5分钟',
  },
  {
    key: '10',
    unit: 'min',
    name: '10分钟',
  },
  {
    key: '30',
    unit: 'min',
    name: '30分钟',
  },
  {
    key: '1',
    unit: 'h',
    name: '1小时',
  },
  {
    key: '2',
    unit: 'h',
    name: '2小时',
  },
  {
    key: '6',
    unit: 'h',
    name: '6小时',
  },
  {
    key: '12',
    unit: 'h',
    name: '12小时',
  },
];

const DataPickerArr = [
  {
    key: 1,
    value: moment(),
  },
  {
    key: 2,
    value: moment().subtract(1, 'days'),
  },
];
