import React, { useCallback, useMemo, useState, useEffect, memo } from 'react';
import { connect } from 'react-redux';
import MapTable from './Fields';
import { getTopScreenId } from 'utils/screen';
import { mappingData, filterData } from 'utils/convert';
import { updateComponentDataConfig } from 'models/component';
import styles from './ComponentDataSource.less';
import { DataContext } from '../RightZoneBar/DataBox/Context/index';
import { EditFilterProps } from '../RightZoneBar/DataBox/index';
import { EditItemProps } from '../RightZoneBar/DataBox/index';
import { scrollChangeSelectBlur } from 'utils/utils';
import ComponentFilter from './Filter/index';
import DataBoxEdit from '../RightZoneBar/DataBox/data';
import { ComponentDataConfigItem, ComponentItem, DataFrom } from 'models/component.types';
import { filterContainersResult } from 'utils/containers';
import PersonalCSV from './PersonalCSV';
import isEqual from 'lodash/isEqual';
import { DataContainersType } from 'models/data-container.types';
import { FiltersType } from 'models/filter.types';
import Filter from './ComponentDataSource/Filter';
import AutoUpdate from './ComponentDataSource/AutoUpdate';
import DataResponse from './ComponentDataSource/DataResponse';
import DataSource from './ComponentDataSource/DataSource';
import IFContainer from '@/components/IFContainer/IFContainer';

type ComponentDataSourceType = {
  componentName: ComponentItem['name'];
  componentId: ComponentItem['id'];
  dataContainers: ComponentItem['dataContainers'];
  dataContainerList: DataContainersType['list'];
  dataFrom: DataFrom;
  dataType: ComponentItem['dataType'];
  dataConfig: ComponentDataConfigItem;
  filters: FiltersType['list'];
  useFilter: ComponentItem['useFilter'];
  usedFilters: ComponentItem['filters'];
  containersFilterResult: {
    [x: number]: any;
  };
  isPerson: boolean;
  updateComponentDataConfig: (params: {
    id: number;
    useFilter?: boolean;
    autoUpdate?: ComponentItem['autoUpdate'];
    data?: any;
    fields?: any;
  }) => any;
};

function ComponentDataSource({
  componentId,
  dataType,
  dataConfig,
  dataContainerList,
  filters,
  useFilter,
  usedFilters,
  containersFilterResult,
  dataContainers: currentDataContainers,
  dataFrom,
  componentName,
  isPerson,
  updateComponentDataConfig,
}: ComponentDataSourceType) {
  const { fields = [], data = [] } = dataConfig || {};
  const [editItem, setEdit] = useState<EditItemProps>();
  const [filterResult, setFilter] = useState<EditFilterProps>();

  const dataContainers = currentDataContainers
    ?.map((d) => dataContainerList?.find((x) => d.id === x.id))
    .filter((d) => d);

  const currentFilters = usedFilters
    .filter((d) => d.enable)
    .map((d) => filters.find((o) => o.id === d.id))
    .filter((o) => o);

  const getContainerDatas = useMemo(() => {
    const result = dataContainers?.map((d) => {
      return d?.id ? containersFilterResult[d?.id] || {} : {};
    });
    return filterContainersResult(result);
  }, [dataContainers]);

  const _data = dataFrom === DataFrom.DATA_CONTAINER ? getContainerDatas : data;
  const resultData = useMemo(() => {
    if (useFilter) {
      return (
        filterData({
          data: _data,
          filters: currentFilters,
          id: componentId,
          name: componentName,
        }) || {}
      );
    }
    return _data;
  }, [useFilter, _data, currentFilters]);

  const comData = useMemo(() => mappingData(resultData, fields), [resultData, fields]);

  const filterProps = useMemo(() => {
    if (filterResult && filterResult.type !== 'close') {
      const { data } = filterResult;
      const props = {
        ...data,
        show: true,
      };
      if (editItem?.data && Array.isArray(editItem?.data.filters)) {
        // 数据容器中过滤器
        const { useFilter, filters } = editItem?.data || {};
        return {
          ...props,
          useFilter,
          originData: _data,
          usedFilters: filters,
        };
      }

      if (Array.isArray(usedFilters)) {
        // 组件自己的过滤器
        return {
          ...props,
          originData: _data,
          useFilter,
          usedFilters,
        };
      }
      return props;
    }
    return {
      show: false,
    };
  }, [filterResult, useFilter, usedFilters, editItem]);

  const dataVisible = useMemo(() => {
    return editItem ? ['edit', 'create'].includes(editItem?.type) : false;
  }, [editItem]);

  const dataContextValue = useMemo(() => {
    return {
      useContainer: !!editItem?.data?.id,
      list: dataContainers,
      onSetEdit: (edit?) => setEdit(edit),
      editItem,
      onOpenFilter: (data?) => {
        setFilter(data);
      },
    };
  }, [editItem, dataContainers]);

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

  useEffect(() => {
    //监听某一个元素的滚动条 隐藏select
    document.querySelector('#data-config-list')?.addEventListener('scroll', scrollChangeSelectBlur);
    return () => {
      document
        .querySelector('#data-config-list')
        ?.removeEventListener('scroll', scrollChangeSelectBlur);
    };
  }, [scrollChangeSelectBlur]);

  const handleUpdate = useCallback(
    (value) => {
      updateComponentDataConfig({ ...value, id: componentId });
    },
    [componentId],
  );

  const onClick = (event, i, e) => {
    if (event.target && event.target.type) {
      return;
    }
    setFilter({
      type: i > 3 ? 'view' : 'edit',
      data: {
        createCode: e.id,
        id: componentId,
        originData: data,
        useFilter: useFilter,
        usedFilters: usedFilters,
      },
    });
  };

  const addFilter = useCallback(() => {
    setFilter({
      type: 'create',
      data: {
        createCode: true,
        id: componentId,
        originData: data,
        useFilter: useFilter,
        usedFilters: usedFilters,
      },
    });
  }, [componentId, data, useFilter, usedFilters]);

  const publicConditional = isPerson && dataType === 'static' && !dataFrom;

  return (
    <DataContext.Provider value={dataContextValue}>
      <div className={styles.content}>
        {/* 字段映射表 */}
        <MapTable data={comData} fields={fields} changeData={handleUpdate} />
        <DataSource />
        {/* ----个人版 and 静态资源  = 隐藏----- */}
        <IFContainer
          conditional={publicConditional}
          thenRender={<PersonalCSV />}
          elseRender={<Filter addFilter={addFilter} onClick={onClick} />}
        />
        <IFContainer
          conditional={!dataFrom && !(isPerson && dataType === 'static') && dataType !== 'ws'}
          thenRender={<AutoUpdate />}
        />
        <IFContainer
          conditional={!publicConditional}
          thenRender={<DataResponse resultData={resultData} />}
        />
        <IFContainer
          conditional={(isPerson ? !(dataType === 'static' && !dataFrom) : true)}
          thenRender={
            <ComponentFilter
              onClose={() => {
                setFilter({
                  type: 'close',
                });
              }}
              {...filterProps}
            />
          }
        />
        <DataBoxEdit visible={dataVisible} />
      </div>
    </DataContext.Provider>
  );
}

const mapStateToProps = ({ filters, componentsById, createApp, user, dataContainers }) => {
  const { componentsChildSelected, layersSelected } = createApp;
  const screenId = getTopScreenId();

  const componentId = componentsChildSelected || layersSelected[0];
  const current = componentsById[componentId] as ComponentItem;

  let dataContainerList, containersFilterResult;

  if (current.dataFrom === DataFrom.DATA_CONTAINER) {
    containersFilterResult = {};
    dataContainerList = [];

    dataContainerList = dataContainers.list.filter((d) => d.screenId === screenId);
    current.dataContainers.forEach((d) => {
      containersFilterResult[d.id] = dataContainers.filterResult[d.id];
    });
  }

  return {
    componentId: componentId,
    componentName: componentsById[componentId]?.name,
    usedFilters: current.filters || [],
    useFilter: current.useFilter, // TODO过滤器开关
    dataConfig: current.dataConfigs[current.dataType],
    dataType: current.dataType,
    autoUpdate: current.autoUpdate,
    dataContainerList: dataContainerList || [],
    dataContainers: current.dataContainers || [],
    filters: filters.list || [],
    dataFrom: current.dataFrom || DataFrom.DEFAULT,
    containersFilterResult: containersFilterResult || {},
    isPerson: user.isPerson,
  };
};

const mapDispatchToProps = {
  updateComponentDataConfig,
};
function areEqual(props, nextProps) {
  return (
    isEqual(props.componentId, nextProps.componentId) &&
    isEqual(props.usedFilters, nextProps.usedFilters) &&
    isEqual(props.useFilter, nextProps.useFilter) &&
    isEqual(props.dataConfig, nextProps.dataConfig) &&
    isEqual(props.dataType, nextProps.dataType) &&
    isEqual(props.autoUpdate, nextProps.autoUpdate) &&
    isEqual(props.dataContainerList, nextProps.dataContainerList) &&
    isEqual(props.dataContainers, nextProps.dataContainers) &&
    isEqual(props.filters, nextProps.filters) &&
    isEqual(props.dataFrom, nextProps.dataFrom) &&
    isEqual(props.containersFilterResult, nextProps.containersFilterResult) &&
    isEqual(props.isPerson, nextProps.isPerson)
  );
}
export default connect(mapStateToProps, mapDispatchToProps)(memo(ComponentDataSource, areEqual));
