// 数据容器
import React, { useState, useCallback, useEffect, useRef, memo, useMemo } from 'react';
import classNames from 'classnames';
import Containers from './Containers';
import styles from '../index.less';
import Data from './data';
import Setting from './Setting';
import { connect } from 'react-redux';
import EasyvModal, { useConfirmRef } from 'components/EasyvModal';
import { DataContext, SettingContext } from './Context/index';
import ComponentFilter from '../../ScreenConfig/Filter';
import { deleteContainer } from 'models/data-container';
import message from 'components/message';
import { ConfigProvider } from '@easyv/react-gui';
import { getContainerWithUsedComponents } from 'utils/containers';
import { getTopScreenId } from 'utils/screen';
import isEqual from 'lodash/isEqual';
export interface DataContainerProps {
  children: React.ReactElement;
  onRecycleCallback: (x) => void;
  deleteScreenData: (x) => any;
  list: any[];
}

export type FilterProps = {
  dataConfigs: {
    static: {
      data: any;
      fields: any;
    };
  };
  events: any[];
  triggers: {
    name: string;
    value: string;
    type?: string;
    fields?: {
      name: string;
      type: string;
      desc: string;
    }[];
    data?: any;
  }[];
};

export interface EditItemProps {
  type: string;
  data?: any;
}

export interface EditFilterProps {
  type: 'edit' | 'view' | 'close' | 'create' | 'init';
  data?: any;
}

function DataContainer({
  list,
  deleteContainer,
  isClose,
  children,
  onRecycleCallback,
  id,
  tenantId,
  screensById,
  panelsById,
  componentsById,
}) {
  const [visible, setVisible] = useState(false);
  const [filterResult, setFilter] = useState<EditFilterProps>();
  const [isOpenSetting, settingOpen] = useState(false); //数据容器管理
  const [editItem, setEdit] = useState<EditItemProps>(); // 数据容器编辑
  const deleteRef = useConfirmRef();

  const containerRef = useRef<HTMLDivElement>(null);
  const getUsedComponents = (id, componentsById) => {
    return (
      getContainerWithUsedComponents({
        id,
        componentsById,
      }) || []
    );
  };

  useEffect(() => {
    !isClose && setVisible(false);
  }, [isClose]);

  const newList = useMemo(() => {
    return list.map((d) => {
      return {
        ...d,
        components: getUsedComponents(d.id, componentsById),
      };
    });
  }, [componentsById, list]);

  const handleClose = useCallback(() => {
    setVisible(false);
  }, []);

  useEffect(() => {
    if (editItem?.type === 'delete') {
      // 删除
      deleteRef.current?.show();
    }
  }, [editItem]);

  useEffect(() => {
    // update
    if (editItem && editItem.data) {
      const item = list.find((d) => d.id === editItem.data.id);
      !isEqual(editItem.data, item) &&
        setEdit({
          type: editItem.type === 'create' ? 'edit' : editItem.type,
          data: {
            ...editItem.data,
            ...item,
          },
        });
    }
  }, [list]);

  useEffect(() => {
    onRecycleCallback?.(visible);
    if (!visible) {
      setEdit({ type: 'init' });
      settingOpen(false);
    }
  }, [visible]);

  useEffect(() => {
    const handleClick = (e) => {
      if (!containerRef.current?.contains(e.target)) {
        const appDOM = document.getElementById('easyv-app');
        if (appDOM && appDOM.contains(e.target)) {
          setVisible(false);
        }
      }
    };

    document.addEventListener('click', handleClick, false);

    return () => {
      document.removeEventListener('click', handleClick, false);
    };
  }, []);

  const handleContainerClick = (e) => {
    e.stopPropagation();
  };

  const handleCommitDelete = useCallback(async () => {
    const { id } = editItem?.data || {};
    const componentIds = getUsedComponents(id, componentsById)?.map((d) => d.id) || [];
    const result = editItem && deleteContainer(id, componentIds);
    setEdit({ type: 'init' });
    if (result) {
      message.success('删除成功');
    }
  }, [editItem, componentsById]);

  const dataVisible = editItem ? ['edit', 'create'].includes(editItem?.type) : false;

  const settingChange = ({ type }) => {
    switch (type) {
      case 'open':
        settingOpen(true);
        break;
      case 'close':
      default:
        settingOpen(false);
    }
  };

  const filterProps = useMemo(() => {
    if (filterResult && filterResult.type !== 'close') {
      const { data } = filterResult;
      const { useFilter, filters } = editItem?.data || {};
      if (Array.isArray(filters)) {
        return {
          ...Object.assign(data, { show: true }),
          useFilter,
          usedFilters: filters,
        };
      }
      return Object.assign(data, { show: true });
    }
    return {
      show: false,
    };
  }, [filterResult, editItem]);
  const settingContextValue = useMemo(() => {
    return {
      onChange: settingChange,
    };
  }, []);
  const dataContextValue = useMemo(() => {
    return {
      list: newList,
      useContainer: true,
      onSetEdit: (edit?) => {
        if (edit && edit.type === 'edit') {
          const { id } = edit.data;
          const item = list.find((d) => d.id === id);
          item &&
            edit &&
            setEdit({
              ...edit,
              data: Object.assign(edit.data, item),
            });
        } else {
          setEdit(edit);
        }
      },
      editItem,
      onOpenFilter: (data?) => {
        setFilter(data);
      },
    };
  }, [editItem, newList]);

  const screenId = getTopScreenId();

  return (
    <ConfigProvider
      assetsUrl={window.appConfig.ASSETS_URL}
      uploadBasePath={`data/${tenantId}/${screenId}`}
      screensById={screensById}
      panelsById={panelsById}
      componentsById={componentsById}
      screenId={screenId}
      stateId={id}>
      <SettingContext.Provider value={settingContextValue}>
        <DataContext.Provider value={dataContextValue}>
          <div className={styles.item} ref={containerRef} onClick={handleContainerClick}>
            <span
              onClick={() => setVisible(true)}
              className={classNames({ [styles.active]: visible })}>
              {children}
            </span>
          </div>
          <Containers visible={visible} onClose={handleClose} />
          <Data visible={dataVisible} />

          <Setting visible={isOpenSetting} />

          <ComponentFilter
            onClose={() => {
              setFilter({
                type: 'close',
              });
            }}
            {...filterProps}
          />
          <EasyvModal.Confirm
            title="删除确认"
            content={
              editItem?.data?.enable
                ? '仍有组件绑定该数据容器，删除后不可逆，确认删除吗？'
                : '此操作执行后不可逆，是否确认删除？'
            }
            ref={deleteRef}
            onOk={handleCommitDelete}
          />
        </DataContext.Provider>
      </SettingContext.Provider>
    </ConfigProvider>
  );
}
const mapStateToProps = ({
  dataContainers,
  createApp,
  user,
  screensById,
  componentsById,
  panelsById,
}) => {
  const screenId = getTopScreenId();
  const { list } = dataContainers;

  const { id } = createApp;
  const { userInfo } = user;
  const { tenantId } = userInfo;
  return {
    list: list.filter((d) => d.screenId === screenId),
    id,
    tenantId,
    screensById,
    componentsById,
    panelsById,
  };
};

export default connect(mapStateToProps, {
  deleteContainer,
})(memo(DataContainer));
