import React, { useCallback, useState } from 'react';
import classNames from 'classnames';
import LayerHeader from './LayerHeader';
import { connect } from 'react-redux';
import SortableList from './SortableList';
import LayerFooter from './LayerFooter';
import styles from './Layers.less';
import { updateLayerName, groupByLayers, cancelGroupLayers, sortLayers, sortLayersDirection, changeLayerStatus } from 'models/screen';
import {
  copyComponents,
  copyComponentsToClipboard,
  copyStyleToClipboard,
  pasteComponents,
  pasteStyle,
  transformLayersToPanel
} from 'models/component';
import { selectLayers, selectLayersWithCtrl, selectLayersWithShift, resetSelect } from 'models/create-app';
import { showContextMenu, hideContextMenu } from '../ContextMenu/models';
import RegisterHotKey from './RegisterHotKey';
import Mousetrap from 'mousetrap';
import { arrayExpand } from 'utils/data-helper';
import { componentOperator } from 'utils/component';
import { useActionModalRef } from 'components/EasyvModal';
import ComponentStylePasteModal from '../ComponentStylePasteModal';
import message from 'components/message';
import { isComponent } from 'utils/utils';
import { ComConfigType } from '../ComponentStylePasteModal/type';
import { getKeysByTreeData, getComponentsComConfigBytargetAndSource, getRenderTreeData } from '../ComponentStylePasteModal/util';
import { Utils } from '@easyv/react-gui';
const { transformToOldConfig, getConfig } = Utils;

interface IProps {
  type?: string;
  disabled?: boolean;
  isTopScreen?: boolean;
  layers: any[];
  layersSelected: (string | number)[];
  mobileConstanst: any;
  constants: any;
  componentsChildSelected: any;
  componentsById: any;
  sortLayers: () => any;
  changeLayerStatus: (status, id?, value?) => any;
  updateLayerName: () => any;
  hideContextMenu: () => any;
  resetSelect: () => any;
  selectLayersWithCtrl: (id) => any;
  selectLayersWithShift: (id) => any;
  selectLayers: (id) => any;
  showContextMenu: (param) => any;
  sortLayersDirection: () => any;
  groupByLayers: () => any;
  cancelGroupLayers: () => any;
  copyComponents: () => any;
  transformLayersToPanel: () => any;
  pasteComponents: () => any;
  pasteStyle: () => any;
  copyComponentsToClipboard: () => any;
  copyStyleToClipboard: () => any;
}

function Layers({
  type,
  disabled,
  isTopScreen,
  layers,
  layersSelected,
  mobileConstanst,
  constants,
  componentsById,
  componentsChildSelected,
  sortLayers,
  changeLayerStatus,
  updateLayerName,
  hideContextMenu,
  resetSelect,
  selectLayersWithCtrl,
  selectLayersWithShift,
  selectLayers,
  showContextMenu,
  sortLayersDirection,
  groupByLayers,
  cancelGroupLayers,
  copyComponents,
  transformLayersToPanel,
  pasteComponents,
  copyComponentsToClipboard,
  copyStyleToClipboard
}: IProps) {
  const ref = useActionModalRef();
  const [comConfigList, setComConfigList] = useState<ComConfigType[]>([]);
  const openModal = () => {
    if (!layersSelected.length) {
      message.error('请先选择组件，再进行样式粘贴');
      return;
    }

    if (layersSelected.some((d) => !isComponent(d))) {
      message.error('只能粘贴样式到组件');
      return;
    }

    const componentIds = componentsChildSelected ? [componentsChildSelected] : layersSelected;
    const components = componentIds.map((d) => componentsById[d]);
    if (!components.every((d) => d)) {
      message.error('组件存在丢失，请刷新后重试');
      return;
    }

    const styleString = sessionStorage.getItem('component_style');

    if (!styleString) {
      return;
    }

    let style: any;

    // 尝试解析剪切板内容
    try {
      style = JSON.parse(styleString);
    } catch (e) {
      message.error('组件样式解析失败');
      return;
    }

    if (!style) {
      message.error('请先复制组件样式');
      return;
    }

    const comData = components.map((item) => {
      const comConfigTreeData = getRenderTreeData(
        getComponentsComConfigBytargetAndSource(
          transformToOldConfig(getConfig(item.config, 'style')),
          transformToOldConfig(getConfig(style.config, 'style'))
        )
      );

      return {
        componentId: item.id,
        componentName: `${item.name}${item.base.version}`,
        sourceConfig: item.config,
        comConfigTreeData,
        copyedConfig: transformToOldConfig(style.config),
        defaultAllKeys: getKeysByTreeData(comConfigTreeData)
      };
    });
    if (!comData.filter((item) => item.comConfigTreeData.length).length) {
      message.error('无可粘贴的组件样式');
      return;
    }
    setComConfigList(comData);
    ref.current?.show();
  };

  const handleSelect = useCallback((e, id) => {
    e.stopPropagation();
    hideContextMenu();
    if (!id) {
      resetSelect();
    } else if (e.metaKey || e.ctrlKey) {
      selectLayersWithCtrl(id);
    } else if (e.shiftKey) {
      selectLayersWithShift(id);
    } else {
      selectLayers(id);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handleContextMenu = useCallback(
    (e, id) => {
      e.stopPropagation();
      e.preventDefault();
      showContextMenu({
        type: 'layer',
        id,
        event: e
      });
    },
    [showContextMenu]
  );

  const handleBatchOption = useCallback(
    (type) => {
      switch (type) {
        case 'lock':
          return Mousetrap.trigger('command+shift+l');
        case 'copy':
          return Mousetrap.trigger('command+d');
        case 'delete':
          return Mousetrap.trigger('del');
        case 'focus':
          return changeLayerStatus('focus');
      }
    },
    [changeLayerStatus]
  );

  const handleToolBarClick = useCallback(
    (type) => {
      if ('groupCollapse' === type) {
        const groups: any = [];
        const groupIds: any = [];
        arrayExpand(
          layers,
          (item) => item.components,
          (item) => {
            if (componentOperator.isGroup(item.id)) {
              groups.push(item);
              groupIds.push(item.id);
            }
          }
        );
        const value = !groups.every((item) => item.collapsed);
        changeLayerStatus('collapsed', groupIds, value);
      }
    },
    [changeLayerStatus, layers]
  );

  const realConstants = type === 'mobile' ? mobileConstanst : constants;
  return (
    <React.Fragment>
      <RegisterHotKey
        type={type}
        sortLayersDirection={sortLayersDirection}
        groupByLayers={groupByLayers}
        cancelGroupLayers={cancelGroupLayers}
        changeLayerStatus={changeLayerStatus}
        copyComponents={copyComponents}
        copyComponentsToClipboard={copyComponentsToClipboard}
        copyStyleToClipboard={copyStyleToClipboard}
        pasteComponents={pasteComponents}
        pasteStyle={openModal}
        transformLayersToPanel={transformLayersToPanel}
        openModal={openModal}
      />
      <div className={styles.container}>
        <div className={classNames(styles.title, { [styles.screen]: isTopScreen })}>图层</div>
        <LayerHeader disabled={disabled} onClick={handleToolBarClick} />
        <SortableList
          type={type}
          layers={layers}
          layersSelected={layersSelected}
          constants={realConstants}
          onDragEnd={sortLayers}
          onSelect={handleSelect}
          onUpdate={changeLayerStatus}
          onContextMenu={handleContextMenu}
          updateName={updateLayerName}
        />
        <LayerFooter disabled={disabled} onClick={handleBatchOption} />
      </div>
      <ComponentStylePasteModal
        onCancel={() => ref.current?.close()}
        comConfigList={comConfigList}
        title="粘贴组件样式"
        onOk={() => ref.current?.close()}
        ref={ref}
      />
    </React.Fragment>
  );
}

const mapStateToProps = ({ createApp, constants, mobileConstants, screensById, user, componentsById }) => {
  const { id, layersSelected, componentsChildSelected } = createApp;
  const screen = screensById[id];
  let isTopScreen = true;
  let layers = [];
  if (screen) {
    const { panelId, mobileId } = screen;
    isTopScreen = !panelId && !mobileId;
    layers = screen.layers;
  }

  return {
    isTopScreen,
    disabled: !layersSelected.length,
    layers,
    layersSelected,
    constants: constants.list,
    mobileConstanst: mobileConstants.list,
    componentsChildSelected,
    componentsById
  };
};

const mapDispatchToProps = {
  selectLayers,
  selectLayersWithCtrl,
  selectLayersWithShift,
  resetSelect,
  sortLayers,
  sortLayersDirection,
  groupByLayers,
  cancelGroupLayers,
  changeLayerStatus,
  updateLayerName,
  copyComponents,
  showContextMenu,
  hideContextMenu,
  pasteComponents,
  pasteStyle,
  copyComponentsToClipboard,
  copyStyleToClipboard,
  transformLayersToPanel
};

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