import * as React from 'react';
import {
  useState,
  useEffect,
  useCallback,
  useMemo,
} from 'react';
import * as moment from 'moment';
import { Link } from 'react-router-dom';
import {
  FastImage,
  FastButton,
  FastDropdown,
  FastMenu,
  FastIcon,
  FastModal,
} from 'components/ui';
import Action from 'components/basic/Action';
import { parseUrlTemplate, transformRequest, findLabel } from 'utils/tool';
import { Component } from 'components/types';
import fetchData from 'utils/fetchData';
import { App } from 'utils/types';
import { exportExcel } from 'utils/export';
import { TableTypes } from './types';

const DEFAULT_PAGE = 1;
const DEFATUL_LIMIT = 10;
const DEFAULT_TOTAL = 0;
const DEFAULT_PAGEINFO = { page: DEFAULT_PAGE, limit: DEFATUL_LIMIT };
// const DEFATUL_ROW_SELECTION = { key: 'key', type: 'checkbox' };

const useTable = (props: TableTypes.TableProps) => {
  const {
    config,
    handle,
    compRef,
    dict,
    filterParams,
    onSetFilterParams,
  } = props;

  const {
    uuid,
    columns = [],
    scroll,
    action = [],
    pagination = {},
    rowSelection,
    ajax,
    notInit,
    isInit,
    notPagination,
    listKey = 'list',
    totalKey = 'total',
  } = config;

  const {
    type: pageType,
    page: pageAlias,
    offset: offsetAlias,
    limit: limitAlias,
  } = pagination as TableTypes.Pagination;

  const isOffsetPagination = pageType === 'offset';

  // 数据
  const [dataSourceState, setDataSourceState] = useState<App.Dict[]>([]);
  // 分页状态
  const [pageInfoState, setPageInfoState] = useState(DEFAULT_PAGEINFO);
  // 数据总数
  const [totalState, setTotalState] = useState(DEFAULT_TOTAL);
  // 表格栏目配置
  const [columnsState, setColumnsState] = useState<App.Dict[]>(columns);
  // 表格选中状态
  const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
  // 表格选中状态存为对象
  const [selectedRowObjs, setSelectedRowObjs] = useState<any[]>([]);
  // 表单加载状态
  const [loading, setLoading] = useState<boolean>(false);

  // 清空多选
  const handleInitSelectedRow = () => {
    setSelectedRowKeys([]);
    setSelectedRowObjs([]);
  };

  // 根据配置，格式化分页参数
  const formatPageInfo = useCallback((pageInfo: TableTypes.PageInfo) => {
    const { limit, page } = pageInfo;
    return {
      [(isOffsetPagination ? offsetAlias : pageAlias) as string]: isOffsetPagination
        ? (page - 1) * limit
        : page,
      [limitAlias]: limit,
    };
  }, [isOffsetPagination, limitAlias, offsetAlias, pageAlias]);

  // 获取表格数据
  const handleFetchData = useCallback(
    (params: App.Dict, pageNo?: number) => {
      setLoading(true);
      const newPageInfoState = { ...pageInfoState };
      if (pageNo) {
        newPageInfoState.page = pageNo;
        setPageInfoState((state) => ({
          ...state,
          page: pageNo,
        }));
      }
      const combinedParams = {
        ...formatPageInfo(newPageInfoState),
        ...filterParams,
        ...params,
      };
      fetchData(ajax, combinedParams)
        .then((data: TableTypes.ResponseData | App.Dict[]) => {
          setLoading(false);
          if (notPagination) {
            // 无分页
            setDataSourceState(data as App.Dict[]);
            setTotalState((data as App.Dict[]).length);
          } else {
            const total = (data as TableTypes.ResponseData)[totalKey];
            const list = (data as TableTypes.ResponseData)[listKey];
            setDataSourceState(list);
            setTotalState(total);
          }

          if (params) {
            delete params.pageNo;
            delete params.pageSize;
            onSetFilterParams({ ...filterParams, ...params });
          }
          handleInitSelectedRow();
        })
        .catch(() => {
          setLoading(false);
        });
    },
    [
      ajax,
      filterParams,
      formatPageInfo,
      notPagination,
      onSetFilterParams,
      pageInfoState,
    ]
  );

  // pageNo改变回调
  const handlePageNoChange = useCallback(
    (val: number) => {
      const { limit } = pageInfoState;
      const combinedParams = {
        ...filterParams,
        ...formatPageInfo(pageInfoState),
        [(isOffsetPagination ? offsetAlias : pageAlias) as string]:
          isOffsetPagination ? (val - 1) * limit : val,
      };
      handleFetchData(combinedParams);
      setPageInfoState((state) => ({
        ...state,
        page: val,
      }));
    },
    [
      formatPageInfo,
      handleFetchData,
      filterParams,
      isOffsetPagination,
      offsetAlias,
      pageAlias,
      pageInfoState,
    ]
  );

  // pageSize改变回调
  const handlePageSizeChange = useCallback(
    (pageSize: number) => {
      const combinedParams = {
        ...filterParams,
        ...formatPageInfo(pageInfoState),
        [limitAlias]: pageSize,
      };
      handleFetchData(combinedParams);
      setPageInfoState((state) => ({
        ...state,
        limit: pageSize,
      }));
    },
    [filterParams, formatPageInfo, handleFetchData, limitAlias, pageInfoState]
  );

  // page（pageNo, pageSize）改变回调
  const handlePageChange = useCallback(
    (page: number, pageSize: number): void => {
      const combinedParams = {
        ...filterParams.current,
        ...formatPageInfo(pageInfoState),
        [(isOffsetPagination ? offsetAlias : pageAlias) as string]:
          isOffsetPagination ? (page - 1) * pageSize : page,
        [limitAlias]: pageSize || pageInfoState.limit,
      };
      handleFetchData(combinedParams);
      setPageInfoState((state) => ({
        ...state,
        page,
        limit: pageSize,
      }));
    },
    [
      filterParams,
      formatPageInfo,
      handleFetchData,
      isOffsetPagination,
      limitAlias,
      offsetAlias,
      pageAlias,
      pageInfoState,
    ]
  );

  const handleColumnsChange = (_columns: App.Dict[]) => {
    setColumnsState(_columns);
  };

  const handleSelectChange = useCallback(
    (_selectedRowKeys: string[], _selectedRows) => {
      setSelectedRowKeys(_selectedRowKeys);
      setSelectedRowObjs(_selectedRows);
    },
    []
  );

  // 判断选中状态
  const isSelectedRow = (actionConfig: Component.Business.Action) => {
    if (!selectedRowKeys.length) {
      FastModal.warning({ title: "提示", content: "请勾选操作项" });
      return Promise.reject();
    }
    const { ajaxKey } = actionConfig;
    const params = {
      [(ajaxKey as string) || (rowSelection as TableTypes.RowSelection).key]:
        selectedRowKeys.join(","),
    };
    return Promise.resolve(params);
  };

  // 导出
  const handleExport = (_action: Component.Business.Action) => {
    const { exportType, fileName, ajax: exportAjax } = _action;
    if (exportType === Component.Business.ExportType.front) {
      exportExcel({ columns, fileName: fileName as string }, dataSourceState);
    } else {
      const { url, fixedParam } = exportAjax;
      const exportParams = { ...filterParams, ...fixedParam };
      const exportUrl = `${url}?${transformRequest(exportParams)}`;
      // console.log('>>>>>>>>>>>', exportParams, exportUrl);
      window.open(exportUrl);
    }
  };

  // 批量二次确认行为
  const handleBatchConfirm = (
    actionConfig: Component.Business.Action,
    params: App.Dict
  ) => {
    const { label, logText, logKey, ajax: ConfirmAjax } = actionConfig;
    return new Promise((resolve, reject) => {
      FastModal.confirm({
        title: label,
        content: (
          <span>
            确认
            {logText || label}
            <span className="fc-orange">
              {selectedRowObjs
                .map((item: App.Dict) => item[logKey])
                .filter((item: string) => item)
                .join(",")}
            </span>
            吗？
          </span>
        ),
        onOk: () => {
          fetchData(ConfirmAjax, params).then(resolve);
        },
        okText: "确认",
        cancelText: "取消",
      });
    });
  };

  // 生成行为按钮
  const createActionBtn = (
    actionConfig: Component.Business.Action,
    data?: App.Dict
  ) => {
    const { type, mode, label } = actionConfig;
    let handleActionClick = null;

    if (type === Component.Business.TriggerType.export) {
      handleActionClick = handleExport;
    } else if (
      type === Component.Business.TriggerType.confirm &&
      mode === "batch"
    ) {
      handleActionClick = () =>
        isSelectedRow(actionConfig).then((params: App.Dict) =>
          handleBatchConfirm(actionConfig, params)
        );
    } else if (mode === "batch") {
      handleActionClick = () => isSelectedRow(actionConfig);
    }
    return (
      <Action
        key={label}
        moduleUuid={uuid}
        action={actionConfig}
        handle={handle}
        data={data}
        params={filterParams}
        onActionClick={handleActionClick}
      />
    );
  };

  // 生成行为按钮
  const createActionBtns = (
    actionList: Component.Business.Action[],
    data?: App.Dict
  ) =>
    actionList.map((actionItem: any) => {
      const { label, action: childAction } = actionItem;
      if (childAction) {
        return (
          <FastDropdown
            className="ml-8 mt-2 mb-2"
            trigger={["click"]}
            overlay={
              <FastMenu>
                {childAction.map((childActionItem: any) => (
                  <FastMenu.Item>
                    {createActionBtn(childActionItem, data)}
                  </FastMenu.Item>
                ))}
              </FastMenu>
            }
          >
            <FastButton>
              {label}
              <FastIcon.DownOutlined />
            </FastButton>
          </FastDropdown>
        );
      }
      return createActionBtn(actionItem, data);
    });

  // 更新表格配置项
  const updateColumns = () => {
    const newColumns = columns.map((column: TableTypes.Column) => {
      const {
        type,
        separator,
        goto,
        target,
        format,
        action: actionList,
        alias,
        routeHash,
      } = column;
      return {
        ...column,
        render: {
          none: (val: string) => val,
          // 序号
          sequence: (_val: string, _data: App.Dict, index: number) =>
            index + 1 + (pageInfoState.page - 1) * 10,
          // 转义
          alias: (val: string) => {
            if (alias) {
              return findLabel(val, dict[alias]) || val;
            }
            return val;
          },
          // 时间
          time: (val: string) => val && moment(val).format(format),
          // 图片
          image: (val: string) => (
            <FastImage
              src={`https://nimg.ws.126.net/?url=${val}&thumbnail=80x2147483647&quality=80&type=jpg`}
              preview={{
                src: val,
              }}
            />
          ),
          // 百分比
          percent: (val: number) => `${(val / 100).toFixed(2)}%`,
          // 数组转字符串
          arr2str: (val: string[]) => val.join(separator),
          // 字符串转数组
          str2arr: (val: string) => val.split(separator as string).join("\n"),
          // 前端路由
          route: (val: string, data: App.Dict) => {
            if (routeHash) {
              return <Link to={routeHash}>{val}</Link>;
            }
            return (
              <Link to={parseUrlTemplate(goto as string, data)}>{val}</Link>
            );
          },
          // 外链
          link: (val: string, data: App.Dict) => (
            <a
              href={parseUrlTemplate(goto as string, data)}
              target={`_${target}`}
            >
              {val}
            </a>
          ),
          // html展示
          // eslint-disable-next-line react/no-danger
          html: (val: string) => (
            <div dangerouslySetInnerHTML={{ __html: val }} />
          ),
          // 操作
          opts: (_val: string, data: App.Dict) =>
            createActionBtns(actionList as Component.Business.Action[], data),
        }[type],
      };
    });
    setColumnsState(newColumns);
  };

  // 向父组件暴露实例方法
  const getInstance = () => {
    compRef.current = {
      ...compRef.current,
      [uuid]: {
        fetchData: handleFetchData,
        changePage: handlePageNoChange,
      },
    };
  };

  // eslint-disable-next-line react-hooks/exhaustive-deps
  useEffect(updateColumns, [columns, pageInfoState.page]);

  useEffect(getInstance, [compRef, handleFetchData, handlePageChange, uuid]);

  React.useEffect(() => {
    if (isInit) {
      handleFetchData({});
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return {
    notPagination,
    dataSource: dataSourceState,
    pageInfo: pageInfoState,
    total: totalState,
    columns: columnsState,
    scroll,
    actionList: action,
    selectedRowKeys,
    rowSelection,
    notInit,
    loading,
    handlers: useMemo(() => ({
      handlePageNoChange,
      handlePageSizeChange,
      handlePageChange,
      handleColumnsChange,
      handleSelectChange,
    }), [
      handlePageChange,
      handlePageNoChange,
      handlePageSizeChange,
      handleSelectChange,
    ]),
    createActionBtns,
  };
};

export default useTable;
