import React, { useState, useEffect, useRef } from "react";
import lodash from "lodash";

import TR from "./../component/TR";
import ModalFactory from "./../component/ModalFactory";
import CustomHeaderModal from "./../component/CustomHeaderModal";

import { handleAppParams, postNew } from "./../net/request";
import * as formUtils from "./../utils/formUtils";
import * as commonUtils from "./../utils/commonUtils";
import { setObject } from "./../utils/localStorageUtils";
import { CP } from "..";
import { aclCheckPermissions, getHsfHost } from "../net/api";

const displayName = "CpTable";
const CpTable = props => {
  const {
    customKey,
    schema,
    api = {},
    tableProps,
    initData,
    filterParams,
    filterColumns,
    refreshColumns,
    filterTableBtn,
    filterRowBtn,
    getCheckboxProps,
    rowSelectionProps,
    widgets,
    tableTitle,
    searchResponse,
    ...otherProps
  } = props;

  const requestFunc = CP.getCPInfo().requestFunc || postNew;

  const apis = { ...api };

  const tableRef = useRef();
  const hasPageSchema = useRef(false);
  const pageInfo = useRef(formUtils.defaultPageInfo());
  const [tableConfig, setTableConfig] = useState(null);
  // 自定义查询、表头
  const [showCustomColumns, setShowCustomColumns] = useState(false);
  const [showCustomSearch, setShowCustomSearch] = useState(false);
  const customColumnsInfo = useRef({});
  const customSearchInfo = useRef({});

  useEffect(() => {
    if (schema) {
      try {
        pageInfo.current = schema;
        hasPageSchema.current = true;
        resetTableConfig(initData);
      } catch (e) {
        commonUtils.log(e);
      }
    }
  }, [schema]);

  useEffect(() => {
    if (
      tableRef.current &&
      hasPageSchema.current &&
      !commonUtils.isEmptyObj(initData)
    ) {
      const search = { ...tableRef.current.getState().search, ...initData };
      tableRef.current.setState({ search });
      setTimeout(() => {
        tableRef.current.refresh();
      }, 100);
    }
  }, [initData]);

  useEffect(() => {
    if (tableRef.current && refreshColumns) {
      resetTableConfig(tableRef.current.getState().search);
    }
  }, [refreshColumns]);

  useEffect(() => {
    if (tableRef.current) {
      tableRef.current.setTitle(tableTitle);
    }
  }, [tableTitle]);

  const resetTableConfig = async (search = {}) => {
    const {
      table,
      form,
      url,
      tableBtn,
      handle,
      tab,
      autoSearch
    } = pageInfo.current;

    const {
      btn: tableHandle,
      acl: tableAcl,
      openCustomColumns
    } = formUtils.getTableBtn(tableBtn?.handleItems);
    const { btn: rowHandle, acl: rowAcl } = formUtils.getTableHandle(
      handle?.handleItems
    );
    const listAction = `$func.${url ? "onSdkSearch" : "getList"}`;
    const { btn: tabHandle, acl: tabAcl } = formUtils.getTableTab(
      // TODO 缺少tab的权限控制
      tab?.handleItems,
      listAction
    );

    const permissionNames = Array.from(
      new Set([...tableAcl, ...rowAcl, ...tabAcl])
    );
    let aclCheckPermissionResults = [];

    // 自定义表列宽度
    const resizeColumns = formUtils.getDicTrue(tableBtn?.resizeColumns);
    // 自定义表头控制
    const customColumns =
      openCustomColumns || formUtils.getDicTrue(tableBtn?.customColumns);
    // 自定义查询项
    const customSearch = formUtils.getDicTrue(tableBtn?.customSearch);
    // 表查询
    const searchList = form?.formItems || [];
    // 显示查询list
    // 获取缓存查询list user+页面标识+类型（search/columns）
    let lastSearchList = CP.customConfigMap[customKey + "search"];
    if (customSearch) {
      // 查询list  新旧merge
      // 有缓存信息时，根据用户信息处理
      const defaultList = searchList.filter(
        item => item.type !== "gudingcanshu_yincangbuxianshi" // 隐藏传参，不展示  ；  但需放置from表单中
      );
      lastSearchList = mergeList(lastSearchList, defaultList, "key");
      // 弹框默认信息
      customSearchInfo.current = {
        defaultList,
        cacheList: lastSearchList
      };
    }

    // 初始化查询值
    let initialValue = {
      // ...(commonUtils.isObj(initTmpData) ? initTmpData : {}),   // initTmpData 通过search传入，则注释
      ...search
    };
    // 是否多选
    const rowSelection = formUtils.getDicTrue(tableBtn?.rowSelection);
    // 枚举 赋值
    const _columns = await formUtils.getTableColumns(table?.columnItems);

    // 显示表列list
    // 获取缓存表列list user+页面标识+类型（search/columns）
    let lastColumnList = CP.customConfigMap[customKey + "columns"];
    // if (customColumns) { // 不管有没有，都赋值数据，
    // 查询list  新旧merge
    // 有缓存信息时，根据用户信息处理
    lastColumnList = mergeList(lastColumnList, _columns, "dataIndex");
    // 弹框默认信息
    customColumnsInfo.current = {
      defaultList: _columns,
      cacheList: lastColumnList
    };
    // }

    const filterSchema = commonUtils.getFunc(form?.filterSchemaFunc, apis);
    // frSchema 支持混合开发
    const _frSchema = formUtils.listTranslSchema(
      customSearch ? lastSearchList : searchList,
      4,
      initialValue
    ); // 第二个参数需配置
    const frSchema = filterSchema ? filterSchema(_frSchema) : _frSchema;
    // 混合开发后组装initialValue
    initialValue = { ...formUtils.getFRInitData(frSchema), ...initialValue };
    // 获取隐藏固定传参
    const defaultFormData = formUtils.getDefaultInitData(searchList);
    // merge初始值
    frSchema.formData = { ...defaultFormData, ...initialValue };

    // 结合用户缓存过滤 columns
    const showColumns = customColumns
      ? lastColumnList.filter(i => i.isSelected ?? true)
      : _columns || [];

    // 结合自定义函数 混合开发 过滤 columns
    const lastColumns = filterColumns
      ? filterColumns(showColumns, initialValue)
      : showColumns;

    // 对长column首项定位left处理
    lastColumns.length > 8 && (lastColumns[0].fixed = "left");

    // 生成schema
    const schema = {
      rowKey: tableBtn?.rowKey || "id",
      columns: lastColumns,
      tableConfig: {
        resizeColumns,
        customColumns: customColumns && !openCustomColumns,
        customSearch,
        setShowCustomColumns,
        setShowCustomSearch,
        resizeTable: columns => {
          // 开启自定义才有缓存功能 保存最新表头宽度数据
          if (customColumns) {
            // 将变更后数据转为Map
            const newMap = commonUtils.arrayKeyToMap(columns, "dataIndex");
            // 将宽度缓存
            lastColumnList = lastColumnList.map(item => {
              if (newMap.has(item.dataIndex)) {
                item.width = newMap.get(item.dataIndex).width;
              }
              return item;
            });

            // 保存表头，存入缓存
            CP.customConfigMap[customKey + "columns"] = lastColumnList;
            setObject("sunmao_customConfigMap", CP.customConfigMap);
            setTimeout(() => {
              commonUtils.behaviorLog("滑动设置表列宽度");
            }, 1);
          }
        },
        rowSelection,
        getCheckboxProps,
        rowSelectionProps
      },
      searchConfig: {
        searchTopRender: commonUtils.getFunc(form?.searchTopRender, apis),
        autoSearch: formUtils.getDicTrue(
          autoSearch || "5fb8b91ae2559fcd82cad4d2"
        ), // ||  (!commonUtils.isEmptyObj(initTmpData) && !tableRef.current), // 自动搜索，功能单一化，故注释
        initialValue, // 恢复默认传参  ，表单级参数
        initData: { ...initData, ...defaultFormData }, // 为页面级参数、可被search覆盖，不可缺失
        schema: frSchema,
        tab: tabHandle ? 0 : -1,
        api: tabHandle || {
          text: "",
          action: listAction
        }
      },
      actionConfig: {
        showCount: parseInt(handle?.showCount || "2"),
        fixed: "right"
      },
      buttonMenu: filterTableBtn ? filterTableBtn(tableHandle) : tableHandle,
      actionList: filterRowBtn ? filterRowBtn(rowHandle) : rowHandle,
      scroll: { x: formUtils.getTableWidth(lastColumns) },
      aclCheckPermissionResults: [],
      tableTitle,
      ...tableProps
    };

    setTableConfig(schema);

    if (permissionNames.length) {
      postNew(
        getHsfHost() + aclCheckPermissions,
        {
          userId: CP.getCPInfo().extParams?.bucId,
          permissionNames
        },
        "checkPermissionResults",
        {},
        "[object Array]"
      ).then(res => {
        aclCheckPermissionResults = res.data;
        setTableConfig({ ...schema, aclCheckPermissionResults });
      });
    }
  };

  /**
   * merge 缓存与线上数据
   * @param {缓存数据} cacheList
   * @param {实时数据} newList
   * @param {数据key} primaryKey
   * @returns  merge后数据
   */
  const mergeList = (cacheList, newList, primaryKey) => {
    let lastList = [];
    try {
      // 将最新数据转为Map
      const newMap = commonUtils.arrayKeyToMap(newList, primaryKey);
      // 删除无效item
      // 更新item最新信息，非必选项保留用户配置
      let tmpItem;
      // 顺序优先缓存
      cacheList.forEach(c => {
        // 最新对象
        tmpItem = newMap.get(c[primaryKey]);
        if (tmpItem) {
          // item未失效
          lastList.push({
            ...tmpItem,
            width: c?.width,
            isSelected:
              formUtils.getDicTrue(tmpItem.isRequired) || c.isSelected, // 必选则必选中，再者为缓存情况（存在从非必选->必选 场景）
            selectedIndex: lastList.length
          });
        }
      });
      // 将最新有效缓存数据转为Map
      const cacheMap = commonUtils.arrayKeyToMap(lastList, primaryKey);
      // 将新增item依次插入尾部
      newList.forEach(n => {
        if (!cacheMap.has(n[primaryKey])) {
          // 缓存不存在时（新增）,加入list尾部
          lastList.push({
            isSelected: formUtils.getDicTrue(
              n.selectTrue || "5fb8b91ae2559fcd82cad4d2"
            ), //  默认支持配置 且默认选中
            ...n,
            selectedIndex: lastList.length
          });
        }
      });
    } catch (e) {
      // 无缓存则初始化处理
      commonUtils.log(e);
      lastList = newList.map((i, index) => ({
        isSelected: formUtils.getDicTrue(
          i.selectTrue || "5fb8b91ae2559fcd82cad4d2"
        ),
        ...i,
        selectedIndex: index
      }));
    }

    return lastList;
  };

  /**
   * 必备函数
   * 表格请求函数
   * 暂支持post请求，因get用长度限制，避免过多参数
   * @param params 搜索项信息
   */
  const onSdkSearch = params => {
    const { url, okPath = "data", totalPath } = pageInfo.current;
    const { current, pageSize } = params;

    // 例如：          服务器返回数据结构                         sdk所需数据结构
    const handleRes = ({ data = [], total = 0, pageSize = 10, ...rest }) => ({
      data,
      pageSize,
      total,
      ...rest
    });
    return requestFunc(
      commonUtils.getUrl(url),
      handleAppParams(params, filterParams),
      okPath
    )
      .then(res => {
        if (!res)
          throw new Error(
            "请求错误，自行处理，该请求可自行设计，只要返回正确数据格式即可！"
          );
        const data = { current, pageSize };
        // 兼容索引处理 精确处理
        let list = commonUtils.getFirstList(res.exactData);
        if (list) data.data = list;
        else data.data = commonUtils.getFirstList(res.data) || [];
        // 数量总数
        data.total =
          lodash.get(res, totalPath || "data.count", 0) ||
          lodash.get(res, "data.total", 0);
        const endData = handleRes(data);
        searchResponse && searchResponse(endData);
        return endData;
      })
      .catch(err => {
        console.error("err", err, displayName);
      });
  };

  const getList = () => {
    return new Promise((resolve, reject) => {
      try {
        const list = JSON.parse(pageInfo.current.table.mockColumn);
        resolve({ data: list, total: list.length });
      } catch {
        reject("mock失败！");
      }
    });
  };
  /**
   * 表格列操作区-暂为弹框操作
   * @param record 行数据
   * @param refresh 表格刷新函数
   * @param handleInfo 操作信息
   */
  const onSdkTableHandle = (record, refresh, handleInfo) => {
    const { content, funcType } = handleInfo;
    const {
      formItems,
      name,
      url,
      okPath,
      okFunc,
      filterSchemaFunc,
      displayType
    } = content || {};
    const apiUrl = commonUtils.getUrl(url);
    const params = { rowInfo: record, ...record };

    switch (funcType) {
      case "34": // 直接请求
      case "35": // 二次确认请求
        reqHandle(
          apiUrl,
          okPath,
          commonUtils.getFunc(okFunc, apis),
          refresh,
          params
        );
        break;
      case "36": // 表单弹框请求
        const filterSchema = commonUtils.getFunc(filterSchemaFunc, apis);
        const listTranslSchema = formUtils.listTranslSchema(
          formItems,
          2,
          record
        );
        if (formUtils.getDicTrue(displayType))
          listTranslSchema.displayType = "column";
        formHandle(
          filterSchema ? filterSchema(listTranslSchema) : listTranslSchema,
          name,
          apiUrl,
          okPath,
          commonUtils.getFunc(okFunc, apis),
          refresh,
          params
        );
        break;
      default:
        break;
    }
  };

  /**
   * 表头操作区-暂为弹框操作
   * @param data 表格数据
   * @param refresh 表格刷新函数
   * @param selectedKeys 选中行key数据，如id
   * @param selectedRows 选中行数据
   * @param handleInfo 操作信息
   */
  const onSdkTableBtn = ({
    data,
    refresh,
    selectedKeys,
    selectedRows,
    handleInfo,
    search
  }) => {
    const { content, funcType } = handleInfo;
    const {
      formItems,
      name,
      url,
      okPath,
      okFunc,
      filterSchemaFunc,
      displayType
    } = content || {};
    const apiUrl = commonUtils.getUrl(url);
    const params = { selectedKeys, ...search };
    try {
      // 自定义 多选查询 key
      params[pageInfo.current?.tableBtn?.rowSelectionCustomKey] = selectedKeys;
    } catch {}

    switch (funcType) {
      case "34": // 直接请求
      case "35": // 二次确认请求
        reqHandle(
          apiUrl,
          okPath,
          commonUtils.getFunc(okFunc, apis),
          refresh,
          filterParams ? filterParams(params, handleInfo) : params
        );
        break;
      case "36": // 表单弹框请求
        const filterSchema = commonUtils.getFunc(filterSchemaFunc, apis);
        const listTranslSchema = formUtils.listTranslSchema(formItems, 2);
        if (formUtils.getDicTrue(displayType)) {
          listTranslSchema.displayType = "column";
        }
        formHandle(
          filterSchema ? filterSchema(listTranslSchema) : listTranslSchema,
          name,
          apiUrl,
          okPath,
          commonUtils.getFunc(okFunc, apis),
          refresh,
          params
        );
        break;
      case "38": // 自定义表头配置
        setShowCustomColumns(true);
        break;
      default:
        break;
    }
  };

  const reqHandle = async (url, okPath, okFunc, refresh, params) => {
    let loading = ModalFactory.loading();
    return requestFunc(
      url,
      handleAppParams(params),
      okPath,
      {},
      false,
      loading
    ).then(res => {
      try {
        loading.destroy();
      } catch {}
      if (okFunc) okFunc(res, refresh, commonUtils.splitParams(params));
      else refresh && refresh();
    });
  };
  /**
   * 按键事件  -  表单弹框
   * @param formSchema  表单内容
   * @param title 表单名称
   * @param okPath 自定义请求成功标示
   * @param url 请求url
   * @param okFunc  自定义成功调用函数
   * @param refresh  表格刷新函数
   */
  const formHandle = (
    formSchema,
    title,
    url,
    okPath,
    okFunc,
    refresh,
    params
  ) =>
    ModalFactory.showModalForm({
      formSchema,
      widgets,
      width: 1000,
      title,
      request: {
        okPath,
        url,
        params,
        handleOk: (formData, validate) => {
          if (validate.length) return false;
          return true;
        },
        onSuccess: (res, formData) => {
          if (okFunc) okFunc(res, refresh, params, formData);
          else refresh && refresh();
        }
      }
    });

  return tableConfig ? (
    <>
      <CustomHeaderModal
        fieldNames={{
          behaviorName: "自定义表列展示",
          customKey: customKey + "columns",
          key: "dataIndex",
          label: "label"
        }}
        show={showCustomColumns}
        handleCancel={() => setShowCustomColumns(false)}
        onChange={() => {
          setShowCustomColumns(false);
          resetTableConfig(tableRef.current.getState().search);
        }}
        {...customColumnsInfo.current}
      />
      <CustomHeaderModal
        fieldNames={{
          behaviorName: "自定义查询展示",
          customKey: customKey + "search",
          key: "key",
          label: "label"
        }}
        show={showCustomSearch}
        handleCancel={() => setShowCustomSearch(false)}
        onChange={() => {
          setShowCustomSearch(false);
          resetTableConfig(tableRef.current.getState().search);
        }}
        {...customSearchInfo.current}
      />
      <TR
        customKey={customKey}
        ref={tableRef}
        schema={tableConfig}
        api={{
          getList,
          ...apis,
          onSdkTableHandle,
          onSdkTableBtn,
          onSdkSearch
        }}
        widgets={widgets}
        {...otherProps}
      />
    </>
  ) : null;
};

export default React.memo(CpTable);
