import React from 'react';
import { connect } from 'react-redux';
import { getComponentDimension, getGroupDimension, componentOperator, batchModifComponentConfig } from 'utils/component';
import { updateComponentConfig, hybridUpdate } from 'models/component';
import styles from './AlignConfiguration.less';
import { screenOperator } from 'utils/screen';
import isNumber from 'lodash/isNumber';
import { changeLayerStatus } from 'models/screen';
import { getId } from 'utils/interaction';
import GroupConfig from './GroupConfig';
import { isComponent, isGroup, isGeneralPanel } from 'utils/utils';
import EasyGUI, { updateArrayConfig, Utils } from '@easyv/react-gui';

const { getConfig } = Utils;

const config = [
  {
    name: '对齐',
    className: 'align',
    show: 2,
    buttons: [
      {
        tooltip: '顶部对齐',
        value: 'top',
        className: 'icon-_top iconfont'
      },
      {
        tooltip: '垂直居中对齐',
        value: 'middle',
        className: 'icon-_middle1 iconfont'
      },
      {
        tooltip: '底部对齐',
        value: 'bottom',
        className: 'icon-_bottom iconfont'
      },
      {
        tooltip: '左对齐',
        value: 'left',
        className: 'icon-_left iconfont'
      },
      {
        tooltip: '水平居中对齐',
        value: 'center',
        className: 'icon-_middle iconfont'
      },
      {
        tooltip: '右对齐',
        value: 'right',
        className: 'icon-_right iconfont'
      }
    ]
  },
  {
    name: '排列',
    className: 'arrange',
    show: 3,
    buttons: [
      {
        tooltip: '水平分布',
        value: 'horizontal',
        className: 'icon-_1 iconfont'
      },
      {
        tooltip: '垂直分布',
        value: 'vertical',
        className: 'icon-_ iconfont'
      }
    ]
  }
];

// 一个矩形根据类型移动到指定位置 并返回移动结果
function moveShape(moveTarget, moveType, list) {
  const { width, height, id } = moveTarget;
  switch (moveType) {
    // 顶对齐
    case 'top': {
      const top = list.reduce((acc, item) => {
        return (acc = Math.min(acc, item.top));
      }, Number.MAX_VALUE);
      return { ...moveTarget, top };
    }
    // 底对齐
    case 'bottom': {
      const bottom = list.reduce((acc, item) => {
        return (acc = Math.max(acc, item.top + item.height));
      }, 0);
      return { ...moveTarget, top: bottom - height };
    }
    // 左对齐
    case 'left': {
      const left = list.reduce((acc, item) => (acc = Math.min(acc, item.left)), Number.MAX_VALUE);
      return { ...moveTarget, left };
    }
    // 垂直居中对齐
    case 'middle': {
      const [top, bottom] = list.reduce(
        (acc, item) => {
          return [Math.min(item.top, acc[0]), Math.max(item.top + item.height, acc[1])];
        },
        [Number.MAX_VALUE, Number.MIN_VALUE]
      );
      const middle = Math.round(bottom + top) / 2;
      return { ...moveTarget, top: middle - height / 2 };
    }
    // 右对齐
    case 'right': {
      const right = list.reduce((acc, item) => (acc = Math.max(acc, item.left + item.width)), 0);
      return { ...moveTarget, left: right - width };
    }
    // 水平居中
    case 'center': {
      const [left, right] = list.reduce(
        (acc, item) => {
          return [Math.min(acc[0], item.left), Math.max(acc[1], item.left + item.width)];
        },
        [Number.MAX_VALUE, Number.MIN_VALUE]
      );
      const center = Math.round((left + right) / 2);
      return { ...moveTarget, left: center - width / 2 };
    }
    // 水平分布
    case 'horizontal': {
      const { sumWidth, left, right } = list.reduce(
        (acc, item) => {
          return {
            sumWidth: acc.sumWidth + item.width,
            left: Math.min(acc.left, item.left),
            right: Math.max(acc.right, item.left + item.width)
          };
        },
        { sumWidth: 0, left: Number.MAX_VALUE, right: Number.MIN_VALUE }
      );
      const space = (right - left - sumWidth) / (list.length - 1);
      let offsetLeft = 0;
      list
        .slice()
        .sort((a, b) => a.left - b.left)
        .every((item) => {
          if (item.id === id) return false;
          return (offsetLeft += item.width + space);
        });
      return { ...moveTarget, left: left + offsetLeft };
    }
    // 垂直分布
    case 'vertical': {
      const { sumHeight, top, bottom } = list.reduce(
        (acc, item) => {
          return {
            sumHeight: acc.sumHeight + item.height,
            top: Math.min(acc.top, item.top),
            bottom: Math.max(acc.bottom, item.top + item.height)
          };
        },
        { sumHeight: 0, top: Number.MAX_VALUE, bottom: Number.MIN_VALUE }
      );
      const space = (bottom - top - sumHeight) / (list.length - 1);
      let offsetTop = 0;
      list
        .slice()
        .sort((a, b) => a.top - b.top)
        .every((item) => {
          if (item.id === id) return false;
          return (offsetTop += item.height + space);
        });
      return { ...moveTarget, top: top + offsetTop };
    }
  }
}

function AlignConfiguration({ layersSelected, configEdit, commonConfig, onAlignClick, onConfigChange, groupConfig }) {
  return (
    <div className={styles.container}>
      <div className={styles.configtitle}>对齐设置</div>
      <div className={styles.align}>
        {config.map((item, index) => {
          const show = layersSelected.length >= item.show;

          return (
            <div key={index} className={item.className + ' ant-row'}>
              <div className="ant-col-6">
                <label>{item.name}</label>
              </div>
              <div className={'ant-col-18 ' + (!show && 'disabled')}>
                {item.buttons.map((icon, index) => {
                  return (
                    <span key={index} title={icon.tooltip} onClick={() => onAlignClick(icon.value)}>
                      <i className={icon.className} />
                    </span>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>
      {configEdit && (
        <ConfigEditor
          config={commonConfig.config}
          type={commonConfig.type}
          onChange={(type, value) => onConfigChange(commonConfig.type, type, value)}
        />
      )}
      {groupConfig && <GroupConfig />}
    </div>
  );
}

function ConfigEditor({ type, config, onChange }) {
  if (type === 'panel') return null;
  const componentConfig = getConfig(config, 'style');

  return <EasyGUI config={componentConfig} onFieldsChange={(params) => onChange('config', params)} />;
}

function mapStateToProps({ createApp, panelsById, componentsById, screensById }) {
  const { layersSelected, id: screenId } = createApp;
  const layers = screensById[screenId].layers;

  // 判断是否展示配置
  const configEdit = !!layersSelected.reduce((prev, next) => {
    if (prev === false) return false;
    if (isNumber(prev) && isNumber(next)) {
      return componentsById[prev] && componentsById[next] && componentsById[prev].base.module_name === componentsById[next].base.module_name
        ? next
        : false;
    }
    return isGeneralPanel(prev) && isGeneralPanel(next) ? next : false;
  });

  let commonConfig: any = null;

  // 批量编辑配置以选中的第一个为准
  if (configEdit) {
    const firstId = layersSelected[0];
    const type = isGeneralPanel(firstId) ? 'panel' : 'component';
    commonConfig = {
      type,
      hideDefault: screenOperator.findLayerById(firstId, layers).hideDefault,
      config: type === 'panel' ? panelsById[getId(firstId) as number]?.config : componentsById[firstId]?.config
    };
  }

  const groupConfig = getGroupConfig();

  return {
    screenId,
    layers,
    layersSelected,
    componentsById,
    panelsById,
    configEdit,
    commonConfig,
    groupConfig
  };

  // 判断是否展示组配置
  function getGroupConfig() {
    const groupEditable = !!layersSelected.reduce((prev, next) => {
      if (prev === false) return false;
      return isGroup(prev) && isGroup(next) ? next : false;
    });
    return groupEditable ? true : false;
  }
}

const mapDispatchToProps = (dispatch) => ({
  onAlignClick: (value) => {
    dispatch((dispatch, getState) => {
      const { createApp, componentsById, panelsById, screensById } = getState();
      const { layersSelected, id: screenId } = createApp;
      const screen = screensById[screenId];
      // 1. 收集所有选中的组件、动态面板
      const selectedDimensions = layersSelected.map((id) => {
        if (isComponent(id)) {
          return { id, ...getComponentDimension(componentsById[id].config) };
        } else if (isGroup(id)) {
          const dimensions = screenOperator
            .getComponentsFromSelectedLayers(id, screen.layers)
            .map((id) => {
              if (isComponent(id)) {
                const component = componentsById[id];
                const dimension = getComponentDimension(component.config);
                return { id, ...dimension };
              } else if (isGeneralPanel(id)) {
                const panel = panelsById[getId(id) as number];
                const { config } = panel;
                const { width, height, left, top } = config;
                return { id, width, height, left, top, config };
              }
            })
            .filter((d) => d);
          const groupDimension = getGroupDimension(dimensions);
          return { ...groupDimension, id, children: dimensions };
        } else if (isGeneralPanel(id)) {
          const panel = panelsById[getId(id) as number];
          const { config } = panel;
          const { width, height, top, left } = config;
          return { id, width, height, left, top, config };
        }
      });

      const componentStates: any = [];
      const panelStates: any = [];
      // 区分一下panel和component
      function updateByType({ id, x, y }) {
        if (isGeneralPanel(id)) {
          panelStates.push({
            id: getId(id),
            updateData: {
              config: { left: x, top: y }
            }
          });
          return;
        }
        componentStates.push({
          componentId: id,
          updateData: {
            config: componentOperator.moveTo({ x, y, configs: componentsById[id].config })
          }
        });
      }

      // 2. 根据顶层组件和对齐方式计算目标位置
      // 3. 通过目标位置和组件属性计算偏移量
      selectedDimensions.forEach((item) => {
        const { left: newLeft, top: newTop, id } = moveShape(item, value, selectedDimensions);
        // group内组件的偏移量根据最外层group计算
        if (isGroup(item.id)) {
          const offsetX = newLeft - item.left;
          const offsetY = newTop - item.top;
          item.children.map((item) => {
            updateByType({
              id: item.id,
              x: Math.round(item.left + offsetX),
              y: Math.round(item.top + offsetY)
            });
          });
        } else {
          updateByType({
            id,
            x: Math.round(newLeft),
            y: Math.round(newTop)
          });
        }
      });

      // 4. 更新位置
      dispatch(hybridUpdate({ component: componentStates, panel: panelStates }));
      // if (componentStates.length) dispatch(updateComponentConfig(componentStates));
      // if (panelStates.length) dispatch(updatePanel(panelStates));
    });
  },
  onConfigChange: (type, optionType, value) => {
    dispatch((dispatch, getState) => {
      const { componentsById, createApp } = getState();
      const { layersSelected } = createApp;
      if (type === 'component') {
        switch (optionType) {
          case 'hideDefault':
            return dispatch(changeLayerStatus('hideDefault', layersSelected, value));
          case 'lock': {
            const newState = layersSelected.map((id) => ({
              componentId: id,
              updateData: {
                config: updateArrayConfig(componentsById[id].config, {
                  path: ['chart', 'dimension', 'chartDimension'],
                  value: value,
                  field: 'lock'
                })
              }
            }));
            return dispatch(updateComponentConfig(newState));
          }
          case 'config': {
            return dispatch(updateComponentConfig(batchModifComponentConfig(componentsById, value, layersSelected)));
          }
        }
      }
    });
  }
});

export default connect(mapStateToProps, mapDispatchToProps)(AlignConfiguration);
