<script setup>
import { ref, computed, watch, useSlots, onMounted, nextTick, inject } from 'vue'
import { COMP_NAME } from './constant'
import { isBoolean, isUndefined, isString, isObject, isArray } from '../utils/assist'
import VForm from '../VForm/index.vue'
import VTable from '../VTable/index.vue'
import FoldBar from './FoldBar.vue'

defineOptions({
  name: COMP_NAME
})
// props
const props = defineProps({
  searchConfig: {
    // 搜索区域配置
    type: [Object, Boolean],
    validator(val) {
      if (isObject(val) && !isArray(val.fields)) {
        throw new Error(`${COMP_NAME}:searchConfig中的fields需为Array类型`)
      }
      return true
    }
  },
  tableConfig: {
    type: [Object, Boolean],
    required: true,
    validator(val) {
      if (isObject(val) && !isArray(val.columns)) {
        throw new Error(`${COMP_NAME}:tableConfig中的columns需为Array类型`)
      }
      return true
    }
  },
  tableData: {
    // 表格数据
    type: Array
  },
  pageConfig: {
    // 分页配置
    type: Object
  },
  total: {
    // 总页数
    type: Number,
    default: 0
  },
  loading: {
    // 表格是否加载
    type: [Boolean, Object],
    default: false
  },
  foldable: {
    // 搜索区域是否可折叠
    type: Boolean,
    default: false
  }
})

const emits = defineEmits(['search', 'toggle-fold'])

const CONFIG = inject('CONFIG_SEARCH_TABLE')

// models
const search = defineModel('search', { type: Object, default: {} })
const currentPage = defineModel('currentPage')
const pageSize = defineModel('pageSize')

const collapse = ref(true)
// refs
const root = ref()
const VFormRef = ref()
const VTableRef = ref()

// 表格配置
const FORM_DEFAULT_CONFIG = computed(() => {
  const sConfig = props.searchConfig
  if (isObject(sConfig) && sConfig.columns) {
    return {}
  }
  return { inline: true }
})

const SUMMIT_DEFAULT_CONFIG = {
  text: '搜索',
  loading: false,
  icon: 'Search',
  width: 'auto'
}
const RESET_DEFAULT_CONFIG = {
  text: '重置',
  loading: false,
  icon: 'RefreshRight',
  width: 'auto'
}
// 搜索区域配置
const searchConfig = computed(() => {
  const sConfig = props.searchConfig
  const GLOBAL_CONFIG = CONFIG.searchConfig || {}
  if (isUndefined(sConfig)) return false
  if (isBoolean(sConfig)) {
    if (sConfig) {
      return {
        ...FORM_DEFAULT_CONFIG.value,
        ...GLOBAL_CONFIG,
        submitBtn: { ...SUMMIT_DEFAULT_CONFIG, ...GLOBAL_CONFIG.searchBtn },
        resetBtn: { ...RESET_DEFAULT_CONFIG, ...GLOBAL_CONFIG.resetBtn }
      }
    } else {
      return false
    }
  }
  const { fields, ...rest } = sConfig
  return {
    ...FORM_DEFAULT_CONFIG.value,
    ...GLOBAL_CONFIG,
    ...rest,
    submitBtn: {
      ...SUMMIT_DEFAULT_CONFIG,
      ...GLOBAL_CONFIG.searchBtn,
      ...rest.searchBtn
    },
    resetBtn: { ...RESET_DEFAULT_CONFIG, ...GLOBAL_CONFIG.resetBtn, ...rest.resetBtn }
  }
})

// 搜索域
const fields = computed(() => {
  const sConfig = props.searchConfig
  if (isUndefined(sConfig) || (isBoolean(sConfig) && !sConfig)) {
    return []
  }
  return sConfig.fields
})

// 表格配置
const tableConfig = computed(() => {
  const tConfig = props.tableConfig
  if (isUndefined(tConfig)) return false
  if (isBoolean(tConfig)) {
    if (tConfig) {
      return { columns: [], ...CONFIG.tableConfig }
    } else {
      return false
    }
  }
  const { columns, ...rest } = tConfig
  return { ...CONFIG.tableConfig, ...rest }
})
// 表格列
const columns = computed(() => {
  return props.tableConfig ? props.tableConfig.columns || [] : []
})

// 默认分页配置
const PAGE_DEFAULT_CONFIG = {
  onSizeChange() {
    currentPage.value = 1
    VFormRef.value.submit('size-change')
  },
  onCurrentChange() {
    VFormRef.value.submit('current-change')
  }
}
// 分页区域配置
const pageConfig = computed(() => {
  const pConfig = props.pageConfig
  if (isUndefined(pConfig)) return PAGE_DEFAULT_CONFIG
  if (isBoolean(pConfig)) {
    if (pConfig) {
      return PAGE_DEFAULT_CONFIG
    } else {
      return false
    }
  }
  let defaultPageSize = 10
  if (CONFIG.pageConfig && CONFIG.pageConfig.pageSizes) {
    defaultPageSize = CONFIG.pageConfig.pageSizes[0]
  }
  return {
    ...PAGE_DEFAULT_CONFIG,
    defaultPageSize,
    ...CONFIG.pageConfig,
    ...pConfig
  }
})
// 插槽
const slots = useSlots()
// 搜索区域插槽
const searchAreaSlots = computed(() => {
  let result = []
  fields.value.forEach((item) => {
    getSlot(item, result)
  })
  return result
})
// 表格区域插槽
const tableAreaSlots = computed(() => {
  let result = []
  columns.value.forEach((item) => {
    getSlot(item, result)
  })
  return result
})

function getSlot(item, result = []) {
  const slot = item.slot
  if (isString(slot)) {
    slots[slot] && result.push(slot)
  } else if (isObject(slot)) {
    Object.values(slot).forEach((value) => {
      slots[value] && result.push(value)
    })
  }
  const children = item.children
  if (children && children.length) {
    children.forEach((child) => {
      getSlot(child, result)
    })
  }
}
// 搜索区域折叠响应
function toggleFold() {
  collapse.value = !collapse.value
  emits('toggle-fold', collapse.value)
}
// 搜索区域折叠处理
function handleToggle() {
  // 折叠
  if (collapse.value) {
    const searchEl = VFormRef.value.el
    const searchWidth = searchEl.clientWidth
    const actionWidth = searchConfig.value.actionNewLine
      ? 0
      : searchEl.querySelector('.el-form-action-wrapper').clientWidth
    let maxWidth = searchWidth - actionWidth
    searchEl
      .querySelectorAll('.el-form-item:not(.el-form-action-wrapper)')
      .forEach((item, index) => {
        maxWidth -= item.clientWidth
        if (maxWidth <= 0) {
          fields.value[index].hidden = true
        }
      })
  } else {
    // 展开
    fields.value.forEach((item) => {
      if (item.hidden === true) {
        item.hidden = false
      }
    })
  }
}
watch(collapse, (value) => {
  handleToggle()
})

onMounted(async () => {
  if (props.foldable && collapse.value) {
    await nextTick()
    handleToggle()
  }
})

function onSearch(done, eventType = 'search') {
  if (eventType !== 'current-change') {
    currentPage.value = 1
  }
  emits('search', done, eventType)
}

function onReset(done) {
  currentPage.value = 1
  emits('search', done, 'reset')
}

defineExpose({
  root: root.value,
  get refs() {
    return {
      search: VFormRef.value,
      table: VTableRef.value.refs.table,
      page: VTableRef.value.refs.page
    }
  },
  search() {
    VFormRef.value.submit('search')
  },
  reset() {
    VFormRef.value.reset()
  },
  toggleFold
})
</script>

<template>
  <div ref="root" class="search-table-wrapper" :class="{ foldable }">
    <div class="search-wrapper">
      <!-- 搜索区域前方插槽-->
      <div v-if="slots['search-prepend']" class="search-prepend-wrapper">
        <slot name="search-prepend"></slot>
      </div>
      <!-- 搜索区域-->
      <VForm
        v-if="searchConfig"
        ref="VFormRef"
        v-model="search"
        :fields="fields"
        :config="searchConfig"
        :is-search="true"
        @submit="onSearch"
        @reset="onReset"
      >
        <template v-for="(item, index) in searchAreaSlots" :key="index" #[item]="data">
          <slot :name="item" v-bind="data"></slot>
        </template>
        <template #action-prepend>
          <slot name="action-prepend"></slot>
        </template>
        <template #action-append>
          <slot name="action-append"></slot>
        </template>
      </VForm>
      <!-- 折叠bar-->
      <FoldBar v-if="props.foldable" v-model="collapse" @clickHandle="toggleFold"></FoldBar>
      <!-- 搜索区域后方插槽-->
      <div v-if="slots['search-append']" class="search-append-wrapper">
        <slot name="search-append"></slot>
      </div>
    </div>
    <!-- 表格、分页区域-->
    <VTable
      v-if="tableConfig"
      ref="VTableRef"
      v-model:currentPage="currentPage"
      v-model:pageSize="pageSize"
      :columns="columns"
      :data="props.tableData"
      :config="tableConfig"
      :page-config="pageConfig"
      :loading="props.loading"
      :total="props.total"
    >
      <template v-for="(item, index) in tableAreaSlots" :key="index" #[item]="data">
        <slot :name="item" v-bind="data"></slot>
      </template>
      <template v-if="slots['table-prepend']" #table-prepend>
        <slot name="table-prepend"></slot>
      </template>
      <template v-if="slots['table-append']" #table-append>
        <slot name="table-append"></slot>
      </template>
      <template v-if="slots['page-prepend']" #page-prepend>
        <slot name="page-prepend"></slot>
      </template>
      <template v-if="slots['page-append']" #page-append>
        <slot name="page-append"></slot>
      </template>
    </VTable>
  </div>
</template>

<style>
.search-table-wrapper {
  display: flex;
  flex-direction: column;
  background-color: var(--v-light-bg);
}
.search-table-wrapper .search-prepend-wrapper {
  margin-bottom: var(--v-space-base);
}
.search-table-wrapper .search-append-wrapper {
  margin-bottom: var(--v-space-base);
}
.search-table-wrapper .search-wrapper {
  padding: var(--v-space-base) var(--v-space-base) 0;
  position: relative;
  background-color: var(--v-light-bg);
  border-bottom: 1px dashed var(--v-border-color);
}
.search-table-wrapper.foldable .search-wrapper {
  margin-bottom: calc(var(--v-space-base) / 2);
}
.search-table-wrapper .el-form-item {
  margin-right: var(--v-space-base);
  margin-bottom: var(--v-space-base);
}
.search-table-wrapper .el-form-item .el-select {
  min-width: var(--field-min-width);
}
.search-table-wrapper .v-table-wrapper {
  padding: var(--v-space-base);
}
</style>
