import { defaults, get, has, toArray } from 'lodash-es'
import type { Ref } from 'vue'
import { reactive, ref } from 'vue'
import { usePagination } from './usePagination'
 
type keyPath = Array<string> | string
/**
 * 表格 Hook
 * @param api 返回Promise的接口函数
 * @param params 接口调用传递的参数
 * @param options 配置接口数据路径和加载时机
 * @returns 返回一个数组 [data, refresh, pagination, table],分别是列表数据数组、刷新数据方法、分页属性、和表格属性
 * @example
 * 	<el-table :data="tableData" style="width: 100%" v-loading="table.loading" tooltip-effect="light" row-key="qid" @row-click="table.onCurrentChange" @sort-change="table.onSortChange" border></el-table>
 * @example
 * 	<el-pagination v-model:currentPage="pagination.current" v-model:page-size="pagination.pageSize"
 *			:total="pagination.total" small background @size-change="pagination.onSizeChange" :page-sizes="[10, 20, 50, 100, 200, 500]" @current-change="pagination.onPageChange" layout="total, sizes, prev, pager, next, jumper" />
 * @example
 *      // 搜索参数(函数可以动态获取参数)
 *	    const queryParams = () => {
          const queryParams = executeCode(requestObject?.request[':params'], requestObject?.request.params)
          return queryParams?.value
        }
        // 加载列表数据
 *	    const listApi = (params: Object) => {
 *	      const { api, moduleName } = selectApiByUserRole([QuestionGroupJwApi, QuestionBaseManagementSchoolApi, QuestionBaseManagementTeacherApi, , QuestionGroupExpertApi]);
 *	      return getAPI(api)[`api${moduleName}FindAllQuestionBasePost`](params);
 *	    };
 *	    // 将逗号分隔的字符串变成数组
 *	    const format = (item: any) => {
 *	      item.gidArr = item.gid?.split(',')
 *	      return item;
 *	    }
 *	    const [tableData, refresh, pagination, table] = useTable(listApi, queryParams, {
 *	      path: {
 *	        data: 'data.result.items',
 *	        total: 'data.result.total',
 *	        page: 'page',
 *	        size: 'pageSize',
 *	      },
 *	      immediate: true
 *	   }, format);
 */
export function useTable<T>(
  api: (params: object) => Promise<T>,
  params: object | (() => object) = {},
  options: {
    path?: { data?: keyPath; total?: keyPath; page?: string; size?: string }
    immediate?: boolean
  } = {},
  format?: (item: object) => object,
): [Ref<Array<object>>, (extraData?: object | (() => object)) => object, Pagination, Table] {
  defaults(options, {
    path: {
      data: 'data.list',
      total: 'data.total',
      page: 'pageNum',
      size: 'pageSize',
    },
    immediate: false,
  })
 
  // 使用()=>fn()而不是fn()区别在于后者只是一个值且立即执行
  const [pagination, , , setTotal] = usePagination((extraData?: object) =>
    extraData ? refresh(extraData) : refresh(),
  )
  const data = ref<Array<object>>([])
  const table = reactive({
    loading: false,
    curData: {
      id: '',
    }, // 当前选中数据
    // 按属性进行排序
    onSortChange: (column: Column) => {
      refresh({ field: column.prop, order: column.order })
    },
    // 改变当前选中的行
    onCurrentChange: (val: TableRow = { id: '' }) => {
      table.curData = val
    },
  })
 
  const refresh = (extraData?: object | (() => object)): object => {
    table.onCurrentChange() // 接口刷新就重置当前选中
    const requestData = {
      [options?.path?.page as string]: pagination.current,
      [options?.path?.size as string]: pagination.size,
    }
    if (extraData) {
      if (typeof extraData === 'function') {
        Object.assign(requestData, extraData())
      } else {
        Object.assign(requestData, extraData)
      }
    }
    if (params) {
      if (typeof params === 'function') {
        Object.assign(requestData, params())
      } else {
        Object.assign(requestData, params)
      }
    }
    // 添加查询参数
    table.loading = true
    return api(requestData)
      .then((res) => {
        const dataPath = options.path?.data
        const totalpath = options.path?.total
        if (!dataPath || !totalpath) {
          return []
        }
        const rData = get(res, dataPath, [])
        // 对后端返回的数据进行格式化处理
        if (typeof format === 'function') {
          data.value = rData.map((item: object) => format(item))
        } else {
          data.value = rData
        }
        setTotal(get(res, totalpath, 0))
        // 友好提示
        if (!has(res, dataPath) || !has(res, totalpath)) {
          console.warn('useTable:响应数据缺少所需字段')
        }
      })
      .finally(() => {
        table.loading = false
      })
  }
 
  // 立即执行
  if (options!.immediate) {
    refresh()
  }
 
  return [data, refresh, pagination, table]
}

扩展阅读