import { reactive, ref, computed, watch, unref, onUnmounted } from 'vue'
import { typeOf } from '@/utils/common'
import useFetch from '@/hooks/useFetch'
import useSection from '@/hooks/useSection'
import bus from '@/utils/bus'
import { ElMessage } from 'element-plus'
import useMainStore from '@/store/main'
import type { Ref } from 'vue'
import type {
  ApiKeys,
  BaseMultiplePageQuery,
  MultipleResult,
  ExtractApiParams,
  ExtractApiResponse,
  ExtractMultipleApiResponse,
} from '@/api/api'
import type { PaginationProps } from 'element-plus'
import type { InstanceTable, InstanceElTable } from 'global-type'

type P = Parameters<typeof useFetch>

type ReturnTable<T extends ApiKeys, D extends boolean | OptionalPage = true> = {
  tableRef: Ref<InstanceTable | undefined>
  elTableRef: Ref<InstanceElTable | undefined>
  pagination: Ref<Partial<PaginationProps>>
  currentPage: Ref<number>
  total: Ref<number>
  loading: Ref<boolean>
  data: Ref<D extends false ? ExtractApiResponse<T> : ExtractMultipleApiResponse<T>[]>
  error: unknown
  hasSelected?: Ref<boolean>
  onSectionChange: (rows: ExtractMultipleApiResponse<T>[]) => void
  selectedList: ExtractMultipleApiResponse<T>[]
  fetchTable: () => void
}

type OptionalPage = Partial<BaseMultiplePageQuery>

export type ModelType<T extends ApiKeys> = Omit<ExtractApiParams<T>, keyof BaseMultiplePageQuery>
export type MultipleResponseType<T extends ApiKeys> = ExtractMultipleApiResponse<T>
export type ResponseType<T extends ApiKeys> = ExtractApiResponse<T>

// const DEFAULT_PARAMS: BaseMultiplePageQuery = {
//   pageNumber: 1,
//   pageSize: 10,
// }
const mainStore = useMainStore()
const DEFAULT_PAGINATION: Partial<PaginationProps> = {
  layout: 'prev,pager,next',
}

function isPageQuery(c: any): c is OptionalPage {
  return typeOf(c) === 'object'
}

const useTable = <
  T extends ApiKeys,
  C extends Partial<ModelType<T>> = Partial<ModelType<T>>,
  D extends boolean | OptionalPage = true
>(
  api: T,
  additional?: C,
  pageQuery?: D,
  httpConfig: P[1] = 'post'
): ReturnTable<T, D> => {
  const tableRef = ref<InstanceTable>()
  const DEFAULT_PARAMS: BaseMultiplePageQuery = {
    pageNumber: 1,
    pageSize: 10,
  }
  const modelChange = ref(false)
  const elTableRef = computed(() => {
    return tableRef?.value?.tableRef
  })

  const { hasSelected, onSectionChange, selectedList } = useSection<ExtractMultipleApiResponse<T>>()

  const multipleType = pageQuery !== false

  const baseParams = reactive<BaseMultiplePageQuery>(
    Object.assign(DEFAULT_PARAMS, isPageQuery(pageQuery) ? pageQuery : {})
  )

  const currentPage = computed({
    get() {
      return baseParams.pageNumber
    },
    set(n: number) {
      baseParams.pageNumber = n
      fetchTable()
    },
  })
  // watch(currentPage, (val) => {
  //   fetchTable()
  // })
  watch(
    () => additional,
    () => {
      modelChange.value = true
    },
    { deep: true }
  )
  const payload = computed(() => {
    return Object.assign({}, multipleType ? baseParams : {}, additional || {}) as ExtractApiParams<T>
  })

  const { loading, fetch, cancel, error, result } = useFetch(api, httpConfig)

  const fetchTable = () => {
    cancel()
    if (modelChange.value) {
      baseParams.pageNumber = 1
    }
    fetch(payload.value)
    modelChange.value = false
  }

  const pageCount = computed(() => {
    return multipleType ? (result.value as MultipleResult<ExtractApiResponse<T>>)?.pageCount || 1 : 1
  })

  const total = computed(() => {
    return multipleType
      ? (result.value as MultipleResult<ExtractApiResponse<T>>)?.totalCount || 0
      : (result.value as Array<any>).length || 0
  })

  const data = computed(() => {
    return multipleType
      ? (result.value as MultipleResult<ExtractMultipleApiResponse<T>>)?.result || []
      : (unref(result) as any)
  })

  const pagination = computed(() => {
    return Object.assign({}, DEFAULT_PAGINATION, {
      pageSize: baseParams.pageSize,
      pageCount: pageCount.value,
      total: total.value,
    })
  })
  const isLastPage = computed(() => {
    // return currentPage.value * baseParams.pageSize + 1 > total.value
    return pageCount.value == currentPage.value
  })

  const busFunc1 = () => {
    // if (isLastPage.value) {
    //   ElMessage.warning('当前页已是最后一页')
    // } else {
    currentPage.value = Number(currentPage.value) + 1
    // }
  }
  bus.on('toNextTablePage', busFunc1)

  const busFunc2 = () => {
    console.log('pageCount.value == currentPage.value', pageCount.value, currentPage.value)
    //被useTableCheck告知到了最后一行
    if (isLastPage.value) {
      console.log('当前页已是最后一页: from useTable')
      ElMessage.warning('当前页已是最后一页')
    } else {
      mainStore.setRowNextBottomDialogStatus(true)
    }
  }
  bus.on('atBottomRowFromUseTableCheck', busFunc2)

  const busFunc3 = () => {
    if (isLastPage.value) {
      console.log('当前页已是最后一页: from useTable')
      ElMessage.warning('当前页已是最后一页')
    } else {
      currentPage.value = Number(currentPage.value) + 1
    }
  }
  bus.on('needToNextPageFromUseTableCheck', busFunc3)

  const busFunc4 = () => {
    if (currentPage.value == 1) {
      ElMessage.warning('当前页已是第一页')
    } else if (currentPage.value > 1) {
      currentPage.value = Number(currentPage.value) - 1
    }
  }
  bus.on('needToPrevPageFromUseTableCheck', busFunc4)
  onUnmounted(() => {
    bus.off('toNextTablePage', busFunc1)
    bus.off('atBottomRowFromUseTableCheck', busFunc2)
    bus.off('needToNextPageFromUseTableCheck', busFunc3)
    bus.off('needToPrevPageFromUseTableCheck', busFunc4)
  })
  return {
    tableRef,
    elTableRef,
    hasSelected,
    onSectionChange,
    fetchTable,
    selectedList,
    loading,
    total,
    data,
    pagination,
    currentPage: currentPage,
    error,
  }
}

export default useTable
