import { BasicTableProps, ColumnProps, FetchParams, Pagination, SorterResult } from '@/types/table'

import { ref, unref, ComputedRef, computed, onMounted, watch, reactive, Ref, watchEffect } from 'vue'

import { useTimeoutFn } from '@vueuse/core'
import { buildUUID } from '@/utils/uuid'
import { isFunction, isBoolean, isObject } from '@/utils/is'
import { get, cloneDeep, merge, omit } from 'lodash-es'
import { FETCH_SETTING, PAGE_SIZE } from '../src/const'



interface ActionType {
  getPaginationInfo: ComputedRef<boolean | Pagination>
  setPagination: (info: Partial<Pagination>) => void
  setLoading: (loading: boolean) => void
  clearSelectedRowKeys: () => void
  tableData: Ref<Recordable[]>
}

interface SearchState {
  sortInfo: Recordable
}

export function useTableData(propsRef: ComputedRef<BasicTableProps>, { getPaginationInfo, setPagination, setLoading, clearSelectedRowKeys, tableData }: ActionType, emit: EmitType) {

  const searchState = reactive<SearchState>({
    sortInfo: {},
  })

  const dataSourceRef = ref<Recordable[]>([])
  const rawDataSourceRef = ref<Recordable>({})

  //监听数据
  watchEffect(() => {
  
    tableData.value = unref(dataSourceRef)
  })


  watch(
    () => unref(propsRef).dataSource,
    () => {
      //没有api的话就直接赋值
      const { dataSource, api } = unref(propsRef)
      !api && dataSource && (dataSourceRef.value = dataSource)
    },
    {
      immediate: true
    }
  )

  function handleTableChange(pagination: Pagination, sorter?: SorterResult) {
    const { clearSelectOnPageChange, sortFn } = unref(propsRef)

    //清除选中状态当切换页码的时候
    if (clearSelectOnPageChange) {
      clearSelectedRowKeys()
    }

    //填充页码
    setPagination(pagination)

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

    fetch(params)

  }



  const getDataSourceRef = computed(() => {
    return unref(dataSourceRef)
  })

  //更新table
  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]
  }


  //更新table 中的某一行
  function updateTableDataRecord(key: string | number, value: any, record: Recordable): Recordable | undefined {


    const row = findTableDataRecord(key, value)


    if (row) {
      for (const field in row) {

        if (Reflect.has(record, field)) row[field] = record[field]
      }
      return row
    }
  }

  //删除指定行
  function deleteTableDataRecord(index: number | number[]) {
    if (!dataSourceRef.value || dataSourceRef.value.length == 0) return
    const idxs = !Array.isArray(index) ? [index] : index;
    for (const idx of idxs) {
      dataSourceRef.value.splice(idx, 1);
      unref(propsRef).dataSource?.splice(idx, 1)

    }
    setPagination({
      total: unref(propsRef).dataSource?.length
    })
  }


  function insertTableDataRecord(record: Recordable | Recordable[], index: number): Recordable[] | undefined {
    index = index ?? dataSourceRef.value?.length
    const _record = isObject(record) ? [record as Recordable] : (record as Recordable[])
    unref(dataSourceRef).splice(index, 0, ..._record)
    return unref(dataSourceRef)
  }

  function findTableDataRecord(key: string | number, value) {
    if (!dataSourceRef.value || dataSourceRef.value.length == 0) return

    //后续新增tree 表格
    let ret = dataSourceRef.value.find(r => {
      return r[key] === value
    })

    return ret;
  }



  async function fetch(opt?: FetchParams) {
    const { api, searchInfo, defSort, fetchSetting, beforeFetch, afterFetch, pagination } = unref(propsRef);

    if (!api || !isFunction(api)) return

    try {
      setLoading(true)
      const { pageField, sizeField, listField, totalField } = Object.assign({}, FETCH_SETTING, fetchSetting)
      let pageParams: Recordable = {}

      const { currentPage = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as Pagination

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

      const { sortInfo = {} } = searchState

      let params: Recordable = merge(
        pageParams,
        searchInfo,
        opt?.searchInfo ?? {},
        defSort,
        sortInfo,
        opt?.sortInfo ?? {},
      )

      if (beforeFetch && isFunction(beforeFetch)) {
        params = (await beforeFetch(params)) || params
      }

      const res = await api(params)
      rawDataSourceRef.value = res

      //如果返回的直接是数组
      const isArrayResult = Array.isArray(res)
      let resultItems: Recordable[] = isArrayResult ? res : get(res, listField)

      
      const resultTotal: number = isArrayResult ? res.length : get(res, totalField)
      const otherValue: Recordable = omit(res, [listField, totalField])

      // 假如数据变少，导致总页数变少并小于当前选中页码，通过getPaginationRef获取到的页码是不正确的，需获取正确的页码再次执行
      if (Number(resultTotal)) {
        const currentTotalPage = Math.ceil(resultTotal / pageSize)
        if (currentPage > currentTotalPage) {
          setPagination({
            currentPage: currentTotalPage
          })
          return await fetch(opt)
        }
      }

      if (afterFetch && isFunction(afterFetch)) {

        resultItems = (await afterFetch(resultItems, otherValue)) || resultItems
      }

       

      dataSourceRef.value = resultItems
      setPagination({
        total: resultTotal || 0
      })
      if (opt && opt.page) {
        setPagination({
          currentPage: opt.page || 1
        })
      }
      emit('fetch-success', {
        items: unref(resultItems),
        total: resultTotal
      })
      return resultItems


    } catch (error) {
      emit('fetch-error', error)
      dataSourceRef.value = []
      setPagination({
        total: 0
      })
    } finally {
      setLoading(false)
    }
  }


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

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

  function getRawDataSource<T = Recordable>() {
    return rawDataSourceRef.value as T
  }

  async function reload(opt?: FetchParams) {
    return await fetch(opt)
  }

  onMounted(() => {
    useTimeoutFn(() => {
      unref(propsRef).immediate && fetch()
    }, 16)
  })

  return {
    getDataSourceRef,
    getDataSource,
    getRawDataSource,
    setTableData,
    fetch,
    reload,
    updateTableData,
    updateTableDataRecord,
    deleteTableDataRecord,
    insertTableDataRecord,
    findTableDataRecord,
    handleTableChange
  }

}
