<script lang="ts" setup>
import Utils from '@/common/utils'
import { elIcons } from '@/common/element/element.ts'
import Colls from '@/common/utils/colls.ts'

const props = withDefaults(defineProps<{
  modelValue?: string | string[] | null,
  multiple?: boolean,
  placeholder?: string,
  displayField: string,
  columns?: {
    label: string
    prop: string
  }[]
  loader: (param: any) => Promise<G.PageResult<any>>
}>(), {
  placeholder: '请选择',
  multiple: false,
})

const emits = defineEmits([ 'update:modelValue' ])

const totalCount = ref(0)
const searchForm = Utils.resetAble(reactive<Record<string, any> & G.PageParam>({
  keywords: '',
  current: 1,
  size: 20,
  orders: 'id',
}))
const tableDataList = ref<Record<string, any> & { id: string }[]>([])
const searching = ref(false)

const selectRows = Utils.resetAble(reactive<string[]>([]))

function paging() {
  searching.value = true
  return props.loader(searchForm.$clone())
    .then(res => {
      totalCount.value = res.total ?? 0
      const value = res.records ?? []
      tableDataList.value = value
      return value
    })
    .finally(() => {
      searching.value = false
    })
}

function reset() {
  searchForm.$reset()
  paging()
}

function onOpen() {
  if (props.multiple) {
    if (props.modelValue != null && props.modelValue.length > 0) {
      selectRows.$reset(props.modelValue as string[])
    }
  } else {
    if (props.modelValue != null && props.modelValue.length > 0) {
      selectRows.$reset([ props.modelValue as string ])
    }
  }
  paging()
}

onMounted(onOpen)

function onClose() {
  searchForm.$reset()
}

function onClear() {
  selectRows.$reset([])
  if (props.multiple) {
    emits('update:modelValue', selectRows)
  } else {
    emits('update:modelValue', selectRows.length > 0 ? selectRows[0] : null)
  }
}

function visibleChangeHandler(val: boolean) {
  if (val) onOpen()
  else onClose()
}

function rowClick(val: Record<string, any> & { id: string }) {
  let value: string | string[] | null
  if (props.multiple) {
    const indexOf = selectRows.indexOf(val.id)
    if (indexOf === -1) {
      selectRows.push(val.id)
    } else {
      selectRows.splice(indexOf, 1)
    }
    value = [ ...selectRows ]
  } else {
    const indexOf = selectRows.indexOf(val.id)
    if (indexOf === -1) {
      selectRows.$reset([ val.id ])
    } else {
      selectRows.$reset([])
    }
    value = val.id
  }
  emits('update:modelValue', value)
}

const selectHeader_indeterminate = computed(() => {
  return selectRows.length > 0 && selectRows.length < tableDataList.value.length
})
const selectHeader_checked = computed({
  get() {
    return selectRows.length > 0 && tableDataList.value.length > 0 && selectRows.length === tableDataList.value.length
  },
  set(val) {
    if (props.multiple) {
      if (val) {
        const newData = tableDataList.value.map(it => it.id)
        selectRows.$reset([ ...new Set([ ...selectRows, ...newData ]) ])
      } else {
        const newData = tableDataList.value.map(it => it.id)
        selectRows.$reset(selectRows.filter(it => !newData.includes(it)))
      }
      emits('update:modelValue', selectRows)
    } else {
      const newData = tableDataList.value.map(it => it.id)
      selectRows.$reset(selectRows.filter(it => !newData.includes(it)))
      emits('update:modelValue', selectRows.length > 0 ? selectRows[0] : null)
    }
  },
})

const displayData = computed(() => {
  if (props.multiple) {
    return `已选 ${selectRows.length} 条`
  }
  let data = tableDataList.value
    .filter(it => selectRows.includes(it.id))
    .map(it => ((it as Record<string, any>) [props.displayField] as any) ?? '')
  if (Colls.isEmpty(data)) {
    data = selectRows as string[]
  }
  return data.join('')
})
</script>

<template>
  <ElDropdown class="drop-table"
    closable
    placement="bottom"
    trigger="click"
    @visible-change="visibleChangeHandler">
    <template #default>
      <div>
        <slot :displayData="displayData" name="displayArea">
          <ElInput :model-value="displayData" :placeholder="placeholder" readonly>
            <template #suffix>
              <ElIcon class="clear-btn" @click.stop="onClear">
                <ElIconCircleClose/>
              </ElIcon>
            </template>
          </ElInput>
        </slot>
      </div>
    </template>
    <template #dropdown>
      <div class="drop-table-content">
        <ElForm inline @submit.prevent="paging">
          <slot :searchForm="searchForm" name="searchForm">
            <ElFormItem>
              <ElInput
                v-model="searchForm.keywords"
                placeholder="请输入要搜索的内容"/>
            </ElFormItem>
          </slot>
          <ElFormItem>
            <ElButton :icon="elIcons.Search" :loading="searching" native-type="submit" type="primary">搜索</ElButton>
            <ElButton :icon="elIcons.Refresh" :loading="searching" @click="reset">重置</ElButton>
          </ElFormItem>
        </ElForm>
        <ElDivider class="drop-table-content-divider"/>
        <ElTable
          ref="tableRef"
          :data="tableDataList"
          cell-class-name="table-cell"
          class="table-list selectable"
          empty-text="暂无数据"
          header-row-class-name="table-header"
          row-key="id"
          @row-click="rowClick"
        >
          <ElTableColumn width="50">
            <template #default="{row}">
              <ElCheckbox :model-value="selectRows.includes(row.id)"/>
            </template>
            <template #header>
              <ElCheckbox v-model="selectHeader_checked" :indeterminate="selectHeader_indeterminate"/>
            </template>
          </ElTableColumn>
          <ElTableColumn label="#" type="index"/>
          <slot name="columns">
            <ElTableColumn
              v-for="(item, i) in columns"
              :key="'a-drop-table-'+i"
              :label="item.label"
              :prop="item.prop"/>
          </slot>
        </ElTable>
        <ElDivider class="drop-table-content-divider"/>
        <ElPagination
          v-model:current-page="searchForm.current"
          v-model:page-size="searchForm.size"
          :hide-on-single-page="false"
          :page-sizes="[10, 20, 50, 100, 500]"
          :teleported="false"
          :total="totalCount"
          background layout="total, prev, pager, next, sizes, jumper"
          @change="paging"/>
      </div>
    </template>
  </ElDropdown>
</template>

<style lang="stylus" scoped>
.drop-table {
  width 100%;
}

.clear-btn {
  cursor: pointer;

  &:hover {
    color: #1C6EFF
  }
}

.drop-table-content {
  padding: 18px;
  display: flex;
  flex-direction: column;
  height 400px
}

.drop-table-content-divider {
  margin 10px 0
}

.table-list {
  flex 1;
  margin 0
  width 100%
  height 200px

  &.selectable {
    :deep(.el-table__row) {
      cursor pointer;
    }
  }

  :deep(.table-header) {
    color #454C59

    th {
      background-color #EDF1F7
      font-weight 500
      position relative

      & > div {
        display flex
        gap 5px
        align-items center
      }

      &:not(:first-child) > div::before {
        position: absolute;
        top: 50%;
        left: 1px;
        width: 1px;
        background-color: #D3D7DE;
        transform: translateY(-50%);
        content: "";
        height 50%
      }
    }
  }

  :deep(.table-cell) {
    color #2F3540
  }

  .action-btn {
    width 100%
    display flex
    flex-wrap wrap

    & > button {
      margin 0
    }
  }
}

</style>
