<script setup lang="ts">
import type { PropsParams, TablePaginationSetting } from '@/types/table.ts'
import type { ReqConfig } from '@/types/dataAnalysis.ts'
import { FieldSpecialEffectType } from '@/types/tableText.ts'

import { fuzzySearch, throttleFunc } from '@/utils/common'

import { useTable } from '@/hooks/useTable.ts'
import { useRequest } from '@/hooks/useRequest.ts'
import {
  computed,
  type ComputedRef,
  markRaw,
  nextTick,
  onMounted,
  reactive,
  ref,
  toRaw,
  watch
} from 'vue'

import TableFilterForm from '@/components/table/TableFilterForm/TableFilterForm.vue'
import axiosInstance from '@/utils/axios/axiosInstance.ts'
import TableTools from './TableTools.vue'
import TableColumn from './TableColumn/TableColumn.vue'
import type { ResponseInfo } from '@/types/res.ts'

type TableFilterFormRef = InstanceType<typeof TableFilterForm>

// 查询表单的Ref
const filterFormRef = ref<TableFilterFormRef>()

const { analysisResCode } = useRequest()

// 节流的延迟时间
const throttleTime = 500

const props = withDefaults(defineProps<PropsParams>(), {
  needRowindex: true,
  needAverage: false,
  needTotal: false,
  openFilterQuery: true,
  openPageQuery: true,
  loadingState: false,
  openRemoteReqData: true,
  openRemoteQuery: true
})

const emits = defineEmits(['addNewItem', 'upload', 'downLoad'])

// 加载动画
const loading = ref(false)

// 表格数据
const tableData: Array<any> = reactive([])

// 展开表格数据
const expandTableData: Record<string, Array<any>> = reactive({})

// 分页展开表格数据
const expandPaginationConfig = reactive<Record<string, TablePaginationSetting>>({})

const expandPageData = computed(() => {
  const nowActive = activeExpandTablePageConfig.value
  const { currentPage, limit } = expandPaginationConfig[nowActive]
  if (!expandTableData[nowActive]) return []

  // const data = expandTableData[nowActive].slice((currentPage - 1) * limit, currentPage * limit)

  return expandTableData[nowActive].slice((currentPage - 1) * limit, currentPage * limit)
})

// 现在使用的分页
const activeExpandTablePageConfig = ref<string>('')

// 查询表单的数据
const queryFormData = ref<{ [key: string]: any }>({})

// 分页数据
const paginationConfig = reactive<TablePaginationSetting>({
  currentPage: 1,
  limit: 0,
  total: 0,
  pageSizeList: []
})

// 请求配置
const reqConfig = reactive<ReqConfig>({
  url: '',
  otherOptions: {}
})

// 一些公用方法
const {
  getTableData,
  setTableData,
  computedRowIndex,
  handleCurrentChange,
  handleSizeChange,
  insertAverageRow,
  getDecimalFromRange,
  resetTableData,
  initPageConfig,
  initReqConfig,
  createRowKey,
  downLoadTable
} = useTable(tableData, paginationConfig, props.tableFieldsInfo)

/**
 * 本地使用的数据，只有在使用外部数据的情况下使用
 */
let localTableData: ComputedRef | [] = []
if (!props.openRemoteReqData && props.dataList) {
  if (Array.isArray(props.dataList)) {
    localTableData = computed<Array<any>>(() => {
      let curPage = paginationConfig.currentPage
      let limit = paginationConfig.limit
      let begin = curPage * limit - limit
      let end = curPage * limit

      return tableData.slice(begin, end)
    })
  }
}

/**
 * 获取表格数据
 * @returns [表格数据,数据总数]
 */
const getData = async (): Promise<[Array<any>, number]> => {
  try {
    for (let [k, v] of Object.entries(expandTableData)) {
      if (v) {
        delete expandTableData[k]
      }
    }
    expandRowKeys.value = []
    // expandPageData.value.splice(0, expandPageData.value.length)
    // 使用传入数据源
    // 如果使用前端查询，则需要传入dataList作为数据源
    if (!props.openRemoteReqData) {
      if (props.dataList) {
        return [JSON.parse(JSON.stringify(props.dataList)), 0]
      } else {
        console.error('请传入dataList，没有数据源！')
        return [[], 0]
      }
    } else {
      // 如果需要表格自己请求数据的
      // 必须要传入requestConfig
      if (props.requestConfig) {
        // 当使用远程请求数据源的时候，默认使用远程查询
        reqConfig.otherOptions.offset = (paginationConfig.currentPage - 1) * paginationConfig.limit
        reqConfig.otherOptions.limit = paginationConfig.limit
        return await getTableData(reqConfig.url, reqConfig.otherOptions)
      } else {
        console.error('缺少请求配置')
        return [[], 0]
      }
    }
  } catch (err) {
    console.error('请求错误:', err)
    return [[], 0] // 确保返回 false 表示失败
  }
}

/**
 * 将获取的数据赋值给tableData，同时设置分页数据的总数
 * @param tableList 表格数据
 * @param total 数据总数
 * @returns 设置是否成功
 */
const setData = (tableList: Array<any>, total: number): boolean => {
  try {
    setTableData(tableList, total, props.openPageQuery, props.openRemoteReqData)
    insertAverageRow(props.needAverage, props.openRemoteReqData)
    return true
  } catch (err) {
    console.error(err)
    return false
  }
}

/**
 * 更新表格数据
 * @returns 设置是否成功
 */
const updateTableData = async (): Promise<boolean> => {
  try {
    loading.value = true
    let [tableList, total] = await getData()
    setData(tableList, total)
    return true
  } catch (err) {
    console.log(err)
    return false
  } finally {
    loading.value = false
  }
}

// 包装一下获取数据
const throttleGetData = throttleFunc(updateTableData, 1000)

/**
 * @description 按条件查询，如果开启了分页查询，那么会直接重新查询数据，否则，会根据现有数据进行查询
 */
const queryTableData = () => {
  if (props.openRemoteQuery && props.openRemoteReqData && props.requestConfig) {
    reqConfig.otherOptions = { ...reqConfig.otherOptions, ...queryFormData.value }
    // 需要在查询前清除掉目前的数据，不然会导致之前缓存的数据混入
    //  比如第一页已经缓存了，在第二页重新查询，在切回第一页，还是显示查询前的数据，因为缓存没被清除
    tableData.splice(0, tableData.length)
    updateTableData()
    console.log(reqConfig.otherOptions)
  } else {
    let filteredTable: any[]
    // 过滤出来所有符合formData数据的条件
    if (props.dataList) {
      filteredTable = props.dataList.filter((item) => {
        let state = true
        for (let [k, v] of Object.entries(queryFormData.value)) {
          // 模糊查询，看值是否跟表格中的数据匹配
          if (!fuzzySearch(v, item[k])) {
            state = false
            break
          }
        }
        return state
      })
      paginationConfig.total = filteredTable.length
      tableData.splice(0, tableData.length, ...filteredTable)
    } else {
      console.error('没有数据源')
    }
  }
}

// 把查询方法包装一下，节流
const throttleQueryTableData = throttleFunc(queryTableData, throttleTime)

/**
 * @description: 单独处理拥有均值行的表格每个单元格的样式,均值字段均加粗，其他需要比较的字段根据自身百分比显示颜色
 *              其中使用row-style无效，scope会导致无法覆盖样式
 *               同时由于自定义了表格内容，哪里的样式会覆盖row的样式，所以只能单独对单元格设置
 * @param {*} info  每个单元格的信息
 */
const tableCellStyle = (info: any) => {
  if (info.row.date === '均值')
    return {
      'font-weight': 'bold'
    }
  else if (info.column.property != 'count' && info.column.property != 'date' && props.needAverage) {
    return {
      'background-color': `rgba(59, 157, 247,${getDecimalFromRange(info.row[info.column.property])})`
    }
  } else return {}
}

/**
 * 监听limit的变化，改变后将页码置为1，同时去重新请求数据
 */
const watchLimit = watch(
  () => paginationConfig.limit,
  (newLimit, oldLimit) => {
    if (newLimit !== oldLimit) {
      paginationConfig.currentPage = 1
      if (props.openFilterQuery) {
        filterFormRef.value?.throttleResetQuery()
      } else {
        throttleQueryTableData()
      }
    }
  },
  { deep: true }
)

/**
 * 监听currentPage的变化，如果开启了分页查询，并且当前页发生变化，并且当前页的数据不存在，则重新请求数据
 */
const watchCurPage = watch(
  () => paginationConfig.currentPage,
  (newPage, oldPage) => {
    if (newPage !== oldPage && !tableData[newPage]) {
      updateTableData()
    }
  },
  {
    deep: true
  }
)

// 如果没有开启分页查询，直接关闭这两个监听
if (!props.openPageQuery) {
  watchLimit()
  watchCurPage()
}

// 监听传入的datalist的变化，然后去更新数据
const changeDataList = watch(
  () => [props.dataList],
  () => {
    updateTableData()
  },
  {
    deep: true
  }
)

/**
 * 对传入的props进行检查，对错误配置进行提示
 */
const checkPropsConfig = () => {
  const {
    openFilterQuery,
    queryInfo,
    openPageQuery,
    paginationConfig,
    openRemoteReqData,
    requestConfig,
    openRemoteQuery,
    dataList
  } = props
  if (openFilterQuery && !queryInfo) {
    console.error('请输入查询的配置信息')
  }
  if (openPageQuery && !paginationConfig) {
    console.error('请输入分页配置信息')
  }
  if (openRemoteReqData || openRemoteQuery) {
    if (!requestConfig) {
      console.error('请输入请求配置信息')
    }
  }

  if (!openRemoteReqData) {
    if (!dataList) {
      console.error('请至少确保一个数据源')
    }
    if (openRemoteQuery) {
      console.error('远程查询无效，请开启数据远程请求')
    }
  }
}

/**
 * 监听请求配置的变化，如果开启了查询功能，则需要重置表单后查询
 * 否则直接请求数据
 */
const watchReqConfig = watch(
  () => props.requestConfig,
  () => {
    Object.assign(reqConfig, props.requestConfig)
    if (props.openFilterQuery) {
      filterFormRef.value?.throttleResetQuery()
    } else {
      throttleQueryTableData()
    }
  },
  {
    deep: true
  }
)

/**
 * 不使用远程数据，则不用监听请求数据的变化
 */
if (!props.openRemoteReqData) {
  watchReqConfig()
}

// 如果是使用远程数据源，则取消监听
if (props.openRemoteReqData) {
  changeDataList()
}

/**
 * @description: 表格排序
 * @param {*} data 获取到的数据
 */
const tableSortChange = (data: { column: any; prop: string; order: any }) => {
  filterFormRef.value?.resetFormData()
  let { order } = { ...data }
  if (order === 'ascending') order = 'asc'
  else if (order === 'descending') order = 'desc'
  else order = ''
  reqConfig.otherOptions.order = order
  throttleQueryTableData()
}

/**
 * 删除行
 * @param url 请求地址
 * @param fieldsInfo 行数据
 */
const deleteRow = (url: string, fieldsInfo: any) => {
  axiosInstance
    .post(url, { ...fieldsInfo })
    .then((data) => {
      analysisResCode(data).then(() => {
        if (props.openFilterQuery) {
          filterFormRef.value?.throttleResetQuery()
        } else {
          throttleQueryTableData()
        }
      })
    })
    .catch((err) => {
      console.log(err)
    })
}

/**
 * @description: 外部获取数据
 */
const outGetTableData = () => {
  return toRaw(tableData).flat()
}

const getTotal = () => {
  if (!props.needTotal || !props.totalFunc) {
    return []
  }
  return props.totalFunc(tableData, paginationConfig.total)
}

const getFormQueryData = (): { [p: string]: any } => {
  return markRaw(queryFormData.value)
}

// 定义暴露出去的方法
defineExpose({
  updateTableData,
  resetTableData,
  deleteRow,
  downLoadTable,
  outGetTableData,
  getFormQueryData
})

onMounted(() => {
  initPageConfig(props.paginationConfig)

  initReqConfig(reqConfig, props.requestConfig)

  checkPropsConfig()

  nextTick(() => {
    // changeTableFooterPos()
  })
})

const expandRowKeys = ref<string[]>([])

const getRowKey = (row: any) => {
  const id = row['actionId'] ?? row['id']
  if (!id) {
    console.warn('请检查表格数据，没有可用的ID 作为RowKey，当前使用随机key')
    return createRowKey()
  }
  return id + ''
}

const handleExpand = async (row: any, expandedRows: any[]) => {
  if (!props.expandConfig) return

  let id = row['actionId'] ?? row['id']
  if (!id) {
    console.warn('请检查表格数据，没有可用的ID 作为RowKey，当前使用随机key')
    id = createRowKey()
  }

  // expandRowKeys.value.push(id)
  if (expandedRows.length) {
    //展开
    expandRowKeys.value = [] //先干掉之前展开的行
    if (row) {
      expandRowKeys.value.push(id) //push新的行 (原理有点类似防抖)
    }
  } else {
    expandRowKeys.value = [] //折叠 就清空expand-row-keys对应的数组
  }

  activeExpandTablePageConfig.value = id
  if (!expandPaginationConfig[id]) {
    expandPaginationConfig[id] = {
      currentPage: 1,
      limit: 10,
      total: 0,
      pageSizeList: [10, 20, 30]
    }
  }

  // 有数据后就不要重新请求数据
  // 这里只判断是否已经请求过了，而不判断是否有数据，防止重复请求
  if (expandTableData[id] !== undefined) return
  const params = {
    ...props.expandConfig.expandReqConfig.otherOptions,
    actionId: id + ''
  }
  const res = (await axiosInstance.post(
    props.expandConfig.expandReqConfig.url,
    params
  )) as ResponseInfo
  if (res.code !== 0) {
    ElMessage.error('获取展开信息失败')
    return
  }
  expandTableData[id] = res.data
  expandPaginationConfig[id].total = res.data.length
}

const handleExpandPageChange = (page: number) => {
  const config = expandPaginationConfig[activeExpandTablePageConfig.value]
  config.currentPage = page
}

const handleExpandSizeChange = (size: number) => {
  const config = expandPaginationConfig[activeExpandTablePageConfig.value]
  config.currentPage = 1
  config.limit = size
}

const handleRowClass = (row: any, _rowIndex: number): string => {
  const hasOptions = row.row.haveOption
  return hasOptions ? '' : 'noneExpandIcon'
}
</script>

<template>
  <div class="tableContent">
    <div class="filterBox" v-if="openFilterQuery && queryInfo">
      <div class="filterHeader">
        <span>查询条件</span>
      </div>
      <div class="filterBody">
        <TableFilterForm
          v-model:query-form-data="queryFormData"
          :queryInfo="queryInfo"
          @query="throttleQueryTableData"
          ref="filterFormRef"
        ></TableFilterForm>
      </div>
    </div>
    <!--    <div class="chartContainer" v-if="needChart && props.chartOptions">-->
    <!--      <PieBorderRadius :options="props.chartOptions"></PieBorderRadius>-->
    <!--    </div>-->
    <slot name="chart" v-if="$slots.chart"></slot>

    <div class="tableTools">
      <TableTools
        :table-fields-info="props.tableFieldsInfo"
        :tools-config="props.tools"
        @add="emits('addNewItem')"
        @download="downLoadTable(props.tools?.headerMap)"
        @refresh="throttleGetData"
      ></TableTools>
    </div>

    <div class="tableBox">
      <p class="totalRow" v-if="props.needTotal">
        <span class="totalItemLabel totalItem"> 总计 </span>
        <span class="totalItem" :key="'totalKey' + item" v-for="item in getTotal()">
          {{ item }}
        </span>
      </p>

      <!-- 没有分页的时候需要重新计算一下data -->
      <!--      :show-summary="props.needTotal"-->
      <!--      :summary-method="-->
      <!--      () => {-->
      <!--      if (props.totalFunc) {-->
      <!--      return props.totalFunc(tableData, paginationConfig.total)-->
      <!--      }-->
      <!--      return []    "-->
      <!--      }-->
      <el-table
        :data="
          openRemoteReqData && openRemoteQuery
            ? tableData[paginationConfig.currentPage]
            : localTableData
        "
        style="width: 100%"
        class="tableBody"
        :cell-style="tableCellStyle"
        v-loading="openRemoteReqData ? loading : props.loadingState"
        :row-key="getRowKey"
        :expand-row-keys="expandRowKeys"
        @sort-change="tableSortChange"
        @query="throttleGetData"
        @expand-change="handleExpand"
        table-layout="auto"
        :row-class-name="handleRowClass"
      >
        <el-table-column
          v-if="props.needRowindex"
          align="center"
          label="#"
          type="index"
          :index="computedRowIndex"
        />
        <el-table-column align="center" show-overflow-tooltip type="expand" v-if="props.needExpand">
          <template #default="rowInfo">
            <el-table :data="expandPageData">
              <template v-for="child in props.expandConfig?.expandField" :key="child.name">
                <el-table-column
                  :prop="child.name"
                  :label="child.cnName"
                  align="center"
                  show-overflow-tooltip
                  v-if="child.isShow"
                  :sortable="child.needSort ? 'custom' : false"
                >
                  <template v-slot="scope">
                    <TableColumn
                      :column-config="child"
                      :row="scope.row"
                      :need-average="props.needAverage"
                    ></TableColumn>
                  </template>
                  <!--                              {{ expandTableData[rowInfo.row.actionId] }}-->
                  <!--                  <TableColumn-->
                  <!--                    :column-config="child"-->
                  <!--                    :row="rowInfo.row"-->
                  <!--                    :need-average="rowInfo.needAverage"-->
                  <!--                  ></TableColumn>-->
                </el-table-column>
              </template>
            </el-table>
            <div class="expandPageConfig">
              <el-pagination
                class="userTablePagination"
                background
                :page-size="expandPaginationConfig[rowInfo.row.actionId].limit"
                :page-sizes="expandPaginationConfig[rowInfo.row.actionId].pageSizeList"
                table-layout="fixed"
                layout="prev, pager, next ,jumper ,sizes,total,"
                :total="expandPaginationConfig[rowInfo.row.actionId].total"
                :current-page="expandPaginationConfig[rowInfo.row.actionId].currentPage"
                @current-change="handleExpandPageChange"
                @size-change="handleExpandSizeChange"
              />
            </div>
          </template>
        </el-table-column>
        <template v-for="item in tableFieldsInfo" :key="item.name">
          <el-table-column
            :prop="item.name"
            :label="item.cnName"
            :min-width="item.specialEffect?.type === FieldSpecialEffectType.DROPDOWN ? '170px' : ''"
            align="center"
            show-overflow-tooltip
            v-if="item.isShow"
            :sortable="item.needSort ? 'custom' : false"
          >
            <template v-slot="scope">
              <TableColumn
                :column-config="item"
                :row="scope.row"
                :need-average="props.needAverage"
              ></TableColumn>
            </template>
          </el-table-column>
        </template>

        <slot name="tableOperation"></slot>
      </el-table>
      <div class="userTablePaginationBox" v-if="openPageQuery">
        <el-pagination
          class="userTablePagination"
          background
          :page-size="paginationConfig.limit"
          :page-sizes="paginationConfig.pageSizeList"
          table-layout="fixed"
          layout="prev, pager, next ,jumper ,sizes,total,"
          :total="paginationConfig.total"
          :current-page="paginationConfig.currentPage"
          @current-change="handleCurrentChange"
          @size-change="handleSizeChange"
        />
      </div>
    </div>
  </div>
</template>

<style scoped>
.tableContent {
  margin: 10px auto 20px;
  width: 100%;
  box-shadow:
    0 4px 8px 0 rgba(0, 0, 0, 0.02),
    0 1px 3px 0 rgba(0, 0, 0, 0.02);
}

.filterBox,
.tableBox {
  width: 100%;
}

.filterBox {
  margin-top: 1%;
  min-height: 18%;
  display: flex;
  flex-direction: column;
}

.filterHeader,
.filterBody {
  width: 98%;
  box-sizing: border-box;

  margin: 10px auto;
}

.filterHeader {
  display: flex;
  align-items: center;
  color: black;
  font-size: 16px;
  font-weight: bold;
}

.filterBody {
  display: flex;
  padding: 0 24px;
}

.queryBox {
  width: 10%;
  display: flex;
  justify-content: space-around;
}

.queryBtnBox {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.refreshBtn {
  margin-top: 10%;
  margin-bottom: 10%;
}

.queryPartition {
  height: 90%;
}

.queryForm {
  width: 90%;
  display: flex;
  flex-wrap: wrap;
}

.filterItem {
  /*width: 20%;*/
  display: flex;
  align-items: center;
}

.selectLabelContainer,
.selectSupplement {
  display: flex;
  align-items: center;
}

.selectSupplement {
  margin-left: 5px;
}

.leftTools,
.rightTools {
  width: 10%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.rightTools {
  width: 5%;
}

.tableBox {
  width: 98%;
  margin: 5px auto;
  box-shadow:
    0 4px 8px 0 rgba(0, 0, 0, 0.02),
    0 1px 3px 0 rgba(0, 0, 0, 0.02);
}

.tableBody {
  box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.1);
}

.userTablePaginationBox {
  box-sizing: border-box;
  width: 98%;
  margin: 0 auto;
  padding: 1% 0;
  display: flex;
  justify-content: center;
}

.expandPageConfig {
  /*width: 98%;*/
  /*height: 600px;*/
  box-sizing: border-box;
  width: 98%;
  margin: 0 auto;
  padding: 1% 0;
  display: flex;
  justify-content: center;
}

.leftToolBtn {
  margin-right: 5px;
}

.totalRow {
  padding: 10px 0px;
  display: flex;
  /*justify-content: space-between;*/
}

.totalRow > .totalItemLabel {
  width: 60px;
  font-weight: bold;
}

.totalItem {
  width: 130px;
  margin-right: 15px;
  text-align: center;
}
</style>
