import React, { useEffect, useState, memo } from 'react';
import { connect } from 'react-redux';
import { Button } from '@easyv/antd';
import ComponentDataSource from './ComponentDataSource';
import ComponentInfo from './ComponentInfo';
import MountAnimation from './Animation/Mount';
import CustomEvent from './CustomEvent';
import CustomTrigger from './CustomTrigger';
import ThemeSelect from './ThemeSelect';
import EasyGUI, { ChildrenManage, Utils } from '@easyv/react-gui';
import {
  addChildComponent,
  deleteChildComponent,
  copyChildComponent,
  updateChildComponent,
  updateComponentConfig,
  updateComponentData,
} from 'models/component';
import { changeComponentConfigActiveKey } from 'models/create-app';
import { updateLayersKey, updateHideDefault } from 'models/screen';
import { selectChild, showComponentEditModal } from 'models/create-app';
import { setScreenState } from 'models/screen-detail';
import { deepFindOne, getAssetsUrl } from 'utils/utils';
import Tabs from '../../../../components/Tabs';
import styles from './Configuration.less';
import { getImageRect, getVideoRect } from 'utils/upload';
import { getComponentDimension } from 'utils/component';
import { addUserStaticMaterical } from 'models/material-lib';
import MaterialModal from '../MaterialModal';
import ModelToReplace from '../ModelToReplace';
import message from 'components/message';
import EasyvConfigSpin from 'components/EasyvConfigSpin';
import { useAuth } from 'components/easyUse';
import { modules } from 'constants/authority';
import { clearCustomEvents } from 'models/queue';
import { changeLayerStatus } from 'models/screen';

const TabPane = Tabs.TabPane;

const { updateArrayConfig, getConfig, getValueFromConfig } = Utils;

type SubstituteTs = {
  path: string[];
  value: any;
};
interface FilterType {
  type: string;
  accept: string;
}

function Configuration({
  componentId,
  moduleName,
  config,
  events,
  triggers,
  dataConfigs,
  childrenList,
  componentsChildSelected,
  componentAddable,
  activeKey,
  hideDefault = false,
  updateHideDefault,
  changeActiveKey,
  addChildComponent,
  updateComponentConfig,
  deleteChildComponent,
  copyChildComponent,
  isTrigger = false,
  updateChildComponent,
  selectChild,
  showComponentEditModal,
  addUserStaticMaterical,
  changeLayerStatus,
  setScreenState,
  clearCustomEvents,
  screenState,
  customEvents,
}) {
  const [childrenCollapsed, setChildrenCollapsed] = useState(true);
  const [substitute, setSubstitute] = useState<null | SubstituteTs>(null);
  const [actionId, setActionId] = useState('');
  const [targetNodeId, setTargetNodeId] = useState('');
  const [eventId, setEventId] = useState('');
  const [fileType, setFilter] = useState<FilterType>({} as FilterType);

  const { checkAuth } = useAuth();

  useEffect(() => {
    return () => {
      changeActiveKey('1');
      clearCustomEvents(); // 清除事件queue
      targetNodeId === componentId && changeLayerStatus('focus', componentId);
    };
  }, []);

  useEffect(() => {
    if (Array.isArray(customEvents) && customEvents.length) {
      const firstItem = customEvents?.[0] || {};
      const { targetNodeId, actionId, eventId } = firstItem;
      if (targetNodeId == componentId) {
        // 万事俱备，鉴权完毕，开始执行
        changeActiveKey('3');
        setActionId(actionId);
        setEventId(eventId);
        setTargetNodeId(targetNodeId);
      }
    }
  }, [customEvents, componentId]);

  if (!config && screenState === 1) {
    // 正在加载
    return <EasyvConfigSpin />;
  }

  if (!config) {
    return <div>组件不存在</div>;
  }

  const isMobileScreen = /\/app\/edit\/[0-9]+?\/[0-9]+?$/.test(window.location.pathname);
  let interaction = config
    ? getConfig(config, 'interaction', isMobileScreen ? 'mobile' : 'screen')
    : [];

  function isOldConfig(config: any[] = []) {
    // eslint-disable-next-line no-prototype-builtins
    return config[0] && config[0]?.hasOwnProperty('_name');
  }

  interaction = checkAuth('callback')
    ? interaction
    : isOldConfig(interaction)
    ? interaction.map((d) => ({
        ...d,
        _value: d._value.filter((o) => o._name !== 'callback'),
      }))
    : interaction.map((d) => ({
        ...d,
        value: d.value.filter((o) => o.name !== 'callback'),
      }));

  const handleFieldsChange = async (updates) => {
    const [{ path = [], value }] = updates;

    // 图片/视频 上传后修改图片组件的尺寸
    if (moduleName === 'image' && path.join('.') === 'chart.component.url' && value) {
      try {
        const { width: imageWidth, height: imageHeight } = await getImageRect(getAssetsUrl(value));
        const { width: originWidth, height: originHeight } = getComponentDimension(config);
        const k1 = imageWidth / imageHeight;
        const k2 = originWidth / originHeight;
        const width = k1 > k2 ? originWidth : k1 * originHeight;
        const height = k1 > k2 ? originWidth / k1 : originHeight;

        updates = updates.concat([
          {
            path: ['chart', 'dimension', 'chartDimension', 'width'],
            value: Math.round(width),
          },
          {
            path: ['chart', 'dimension', 'chartDimension', 'height'],
            value: Math.round(height),
          },
        ]);
      } catch (error) {
        console.error(error);
        return;
      }
    } else if (moduleName === 'video' && path.join('.') === 'chart.component.videoUrl' && value) {
      try {
        const { width: imageWidth, height: imageHeight } = await getVideoRect(getAssetsUrl(value));
        const { width: originWidth, height: originHeight } = getComponentDimension(config);
        const k1 = imageWidth / imageHeight;
        const k2 = originWidth / originHeight;
        const width = k1 > k2 ? originWidth : k1 * originHeight;
        const height = k1 > k2 ? originWidth / k1 : originHeight;

        updates = updates.concat([
          {
            path: ['chart', 'dimension', 'chartDimension', 'width'],
            value: Math.round(width),
          },
          {
            path: ['chart', 'dimension', 'chartDimension', 'height'],
            value: Math.round(height),
          },
        ]);
      } catch (error) {
        console.error(error);
        return;
      }
    }

    const newConfig = updateArrayConfig(config, updates);
    updateComponentConfig({
      componentId: componentId,
      updateData: {
        config: newConfig,
      },
    });
  };

  const handleAddChild = (moduleName) => {
    addChildComponent({ componentId, childModuleName: moduleName });
  };

  const styleConfig = getConfig(config, 'style');
  const modalEditConfig = getConfig(config, 'modal');
  const childrenConfig = getConfig(config, 'children');

  const onMaterialChange = async ({
    visible,
    content,
  }: {
    content: string | undefined;
    visible: boolean;
  }) => {
    if (!visible && substitute) {
      const { path = [] } = substitute;
      if (content) {
        const hide = message.loading('更新中...');
        await handleFieldsChange([
          {
            path,
            value: content,
          },
        ]);
        hide();
      }
      setSubstitute(null);
    }
  };

  const onCustomEvents = (updates) => {
    const { value } = updates;
    if (value?.type === 'change') {
      setFilter(value.data);
      setSubstitute(updates);
    } else if (value?.type === 'save') {
      // 保存为素材
      const { accept, value: url } = value.data;
      const thumb = url.split(window.appConfig.ASSETS_URL).pop();
      const hide = message.loading('保存中...');
      addUserStaticMaterical({
        type: /video/.test(accept) ? 2 : /image/.test(accept) ? 1 : 0,
        content: thumb,
        thumb: thumb,
        preview: thumb,
      });
      hide();
      message.success('保存成功');
    }
  };

  return (
    <div className={styles.container}>
      <Tabs type="card" activeKey={activeKey} onChange={changeActiveKey}>
        <TabPane tab="样式" key="1">
          <ComponentInfo />

          {!componentsChildSelected && <ThemeSelect />}

          <div style={{ maxHeight: 'calc(100vh - 186px)', overflowY: 'auto' }}>
            {!componentsChildSelected && childrenConfig && (
              <ChildrenManage
                collapsed={childrenCollapsed}
                childrenAll={childrenConfig.all}
                childrenList={childrenList}
                onCollapsedChange={setChildrenCollapsed}
                onUpdate={updateChildComponent}
                onAdd={handleAddChild}
                onDelete={deleteChildComponent}
                onCopy={copyChildComponent}
                onSelect={selectChild}
                maxLength={15}
              />
            )}

            {fileType.type === 'uploadModel' ? (
              <ModelToReplace
                accept={fileType.accept}
                visible={!!substitute}
                onChange={onMaterialChange}
              />
            ) : ['uploadImage', 'image', 'video'].includes(fileType.type) ? (
              <MaterialModal
                type={fileType.accept}
                visible={!!substitute}
                onChange={onMaterialChange}
              />
            ) : null}

            <EasyGUI
              config={styleConfig}
              onFieldsChange={handleFieldsChange}
              onCustomEvents={checkAuth(modules.resource) ? onCustomEvents : null}
              hideDefault={hideDefault}
              onHideDefaultChange={updateHideDefault}
            />
            {modalEditConfig.length > 0 && (
              <div style={{ padding: 16 }}>
                <Button
                  type="primary"
                  ghost
                  block
                  onClick={() => {
                    showComponentEditModal(componentId);
                    setScreenState('');
                  }}>
                  {modalEditConfig[0].displayName || modalEditConfig[0]._displayName}
                </Button>
              </div>
            )}
          </div>
        </TabPane>

        {dataConfigs.static && dataConfigs.static.data && (
          <TabPane tab="数据" key="2">
            <ComponentInfo />
            <div style={{ height: 'calc(100vh - 162px)', overflowY: 'auto' }} id="data-config-list">
              {!componentsChildSelected && childrenConfig && (
                <ChildrenManage
                  collapsed={childrenCollapsed}
                  childrenAll={componentAddable ? childrenConfig.all : []}
                  childrenList={childrenList}
                  onCollapsedChange={setChildrenCollapsed}
                  onUpdate={updateChildComponent}
                  onAdd={componentAddable ? handleAddChild : undefined}
                  onDelete={deleteChildComponent}
                  onCopy={componentAddable ? copyChildComponent : undefined}
                  onSelect={selectChild}
                  maxLength={15}
                />
              )}
              <ComponentDataSource key={componentId} />
            </div>
          </TabPane>
        )}

        <TabPane tab="交互" key="3">
          <ComponentInfo />
          <div style={{ maxHeight: 'calc(100vh - 156px)', overflowY: 'auto' }}>
            {!componentsChildSelected && childrenConfig && (
              <ChildrenManage
                collapsed={childrenCollapsed}
                childrenAll={childrenConfig.all}
                childrenList={childrenList}
                onCollapsedChange={setChildrenCollapsed}
                onUpdate={updateChildComponent}
                onAdd={handleAddChild}
                onDelete={deleteChildComponent}
                onCopy={copyChildComponent}
                onSelect={selectChild}
                maxLength={15}
              />
            )}
            {/* 载入动画 */}
            {!componentsChildSelected && <MountAnimation />}

            {/* interaction交互列表 */}
            {interaction.length > 0 && (
              <EasyGUI config={interaction} onFieldsChange={handleFieldsChange} />
            )}

            {/* 自定义事件类型 */}
            {isTrigger && (
              <CustomTrigger key={componentId} componentId={componentId} triggers={triggers} />
            )}
            {/* 自定义事件 */}
            <CustomEvent
              eventId={eventId}
              actionId={actionId}
              events={events}
              triggers={triggers}
              staticConfig={dataConfigs.static}
            />
          </div>
        </TabPane>
      </Tabs>
    </div>
  );
}

const mapStateToProps = ({ createApp, screensById, componentsById, user, screenEdit, queue }) => {
  const { id, componentsChildSelected, layersSelected, componentConfigActiveKey } = createApp;
  const componentId = componentsChildSelected || layersSelected[0];
  const component = componentsById[componentId] || {};
  const { base = {}, config, events, triggers, dataConfigs, children = [] } = component;

  const [chart] = config || [];
  const isTrigger = chart?.isTrigger || false;
  const screen = screensById[id];
  let hideDefault = false;
  if (screen) {
    const layer = deepFindOne(screen.layers, (item) => item.id === layersSelected[0]);
    hideDefault = layer && layer.hideDefault;
  }
  const { customEvents } = queue;
  const childrenList = children.reduce((all, item) => {
    const child = componentsById[item];
    if (child) {
      const { id, config, name } = child;
      let show = getValueFromConfig(config, [0], 'show');
      if (show == null) {
        show = true;
      }

      return all.concat({ id, show, name });
    } else {
      return all;
    }
  }, []);

  return {
    componentId,
    isTrigger,
    moduleName: base?.module_name,
    hideDefault,
    screenState: screenEdit.screenState,
    componentsChildSelected,
    config,
    events,
    triggers,
    dataConfigs,
    childrenList,
    customEvents,
    activeKey: componentConfigActiveKey,
    componentAddable: !(window.appConfig.LOCAL && user.userInfo.type === 'education'),
  };
};

const mapDispatchToProps = {
  updateComponentConfig,
  updateComponentData,
  updateLayersKey,
  changeActiveKey: changeComponentConfigActiveKey,
  showComponentEditModal: showComponentEditModal,
  updateHideDefault: updateHideDefault,
  addChildComponent,
  deleteChildComponent,
  copyChildComponent,
  updateChildComponent,
  selectChild,
  setScreenState,
  addUserStaticMaterical,
  clearCustomEvents,
  changeLayerStatus,
};

export default connect(mapStateToProps, mapDispatchToProps)(memo(Configuration));
