import { ref, ComputedRef, unref, computed, onMounted, watchEffect, watch } from 'vue';
import type { BasicTableProps, SorterResult } from '../types/table';
import type { PaginationProps } from '../types/pagination';
import { isFunction, isBoolean } from '@/utils/is';
import { APISETTING, DEFAULTPAGESIZE } from '../const';

export function useDataSource(
  propsRef: ComputedRef<BasicTableProps>,
  { getPaginationInfo, setPagination, setLoading, tableData },
  emit,
) {
  const dataSourceRef = ref<Recordable[]>([]);

  watchEffect(() => {
    tableData.value = unref(dataSourceRef);
  });

  watch(
    () => unref(propsRef).dataSource,
    () => {
      const { dataSource, request }: any = unref(propsRef);
      !request && dataSource && (dataSourceRef.value = dataSource);
    },
    {
      immediate: true,
    },
  );

  const getRowKey = computed(() => {
    const { rowKey }: any = unref(propsRef);
    return rowKey
      ? rowKey
      : () => {
          return 'key';
        };
  });

  const getDataSourceRef = computed(() => {
    const dataSource = unref(dataSourceRef);
    if (!dataSource || dataSource.length === 0) {
      return unref(dataSourceRef);
    }
    return unref(dataSourceRef);
  });

  function tableChange(
    pagination: PaginationProps,
    filters?: Partial<Recordable<string[]>>,
    sorter?: SorterResult,
  ) {
    const { sortFn, filterFn } = unref(propsRef);

    setPagination(pagination);

    const params: Recordable = {};
    if (sorter && isFunction(sortFn)) {
      const sortInfo = sortFn(sorter);
      params.sortInfo = sortInfo;
    }

    if (filters && isFunction(filterFn)) {
      const filterInfo = filterFn(filters);
      params.filterInfo = filterInfo;
    }
    fetch(params);
  }

  async function fetch(opt?, isRestReload?) {
    try {
      setLoading(true);
      const { request, pagination }: any = unref(propsRef);
      if (!request) return;
      //组装分页信息
      const pageField = APISETTING.pageField;
      const sizeField = APISETTING.sizeField;
      const totalField = APISETTING.totalField;
      const listField = APISETTING.listField;
      const itemCount = APISETTING.countField;
      let pageParams = {};
      const { current = 1, pageSize = DEFAULTPAGESIZE } = unref(
        getPaginationInfo,
      ) as PaginationProps;

      if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) {
        pageParams = {};
      } else {
        pageParams[pageField] = (opt && opt[pageField]) || current;
        pageParams[sizeField] = pageSize;
      }

      const params = {
        ...pageParams,
        ...pagination,
        ...opt,
      };

      //如果是重置刷新，重置页码
      if (isRestReload) {
        params[pageField] = 1;
        setPagination({
          current: 1,
        });
      }
      const res = await request(params);
      const resultTotal = res[totalField] || 0;
      const currentPage = res['current'];
      const total = res[itemCount] || 0;
      const results = res[listField] ? res[listField] : [];

      // 如果数据异常，需获取正确的页码再次执行
      if (resultTotal) {
        const currentTotalPage = Math.ceil(total / pageSize);
        if (current > currentTotalPage) {
          setPagination({
            current: currentTotalPage,
            [itemCount]: total,
          });
          return await fetch(opt);
        }
      }

      dataSourceRef.value = results;
      setPagination({
        // [pageField]: currentPage,
        current: currentPage,
        [totalField]: resultTotal,
        [itemCount]: total,
      });
      if (opt && currentPage) {
        setPagination({
         current: currentPage || 1,
        });
      }
      emit('fetch-success', {
        items: unref(results),
        resultTotal,
      });
    } catch (error) {
      console.error(error);
      const totalField = APISETTING.totalField;
      emit('fetch-error', error);
      dataSourceRef.value = [];
      setPagination({
        [totalField]: 0,
      });
    } finally {
      setLoading(false);
    }
  }

  onMounted(() => {
    setTimeout(() => {
      fetch();
    }, 16);
  });

  function setTableData<T = Recordable>(values: T[]) {
    dataSourceRef.value = values;
  }

  function getDataSource<T = Recordable>() {
    return getDataSourceRef.value as T[];
  }

  async function reload(opt?) {
    await fetch(opt);
  }

  async function restReload(opt?) {
    await fetch(opt, true);
  }

  async function updateTableData(index: number, key: string, value: any) {
    const record = dataSourceRef.value[index];
    if (record) {
      dataSourceRef.value[index][key] = value;
    }
    return dataSourceRef.value[index];
  }

  return {
    fetch,
    getRowKey,
    getDataSourceRef,
    getDataSource,
    tableChange,
    setTableData,
    reload,
    restReload,
    updateTableData,
  };
}
