<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { difference } from 'lodash-es'
import { VueDraggable } from 'vue-draggable-plus'
import { ColumnsMap } from '@/config/final'

const emit = defineEmits<{
  (e: 'commit', columns: any[])
}>()

// 左侧隐藏列表
const offList = ref<any[]>([])
// 右侧显示列表
const fixLeftList = ref<any[]>([])
const onList = ref<any[]>([])

const allCount = computed(() => {
  return `全部字段(共${offList.value.length - 1}个)`
})

const selectCount = computed(() => {
  return `显示字段(共${onList.value.length}个)`
})

function generatList() {
  const keys = Object.keys(ColumnsMap)
  // const showStr = 'name'
  // const showKeys = showStr.split(',').map((key: string) => key.toLowerCase())

  for (const key of keys) {
    const { title, fixed, fixLeft, width } = ColumnsMap[key]
    const item = {
      id: key,
      title,
      fix: fixed,
      checked: ColumnsMap[key].fixed,
      width,
    }

    if (!fixed)
      offList.value.push(item)

    if (fixLeft)
      fixLeftList.value.push(item)
  }

  // showList = showKeys.reduce((acc, key) => {
  //   const config = {
  //     id: key,
  //     title: ColumnsMap[key].title || '未配置',
  //     fix: ColumnsMap[key].fixed,
  //   }
  //   return [...acc, config]
  // }, [])

  const fixedList = generateDefaultList()
  const filterList = fixedList.filter((item) => {
    return !item.fixLeft
  })

  onList.value.unshift(...filterList)
  offList.value.unshift(...fixedList)
}

function generateDefaultList() {
  return Object.keys(ColumnsMap).reduce((acc, key) => {
    const { title, fixed, fixLeft, width } = ColumnsMap[key]

    if (fixed) {
      const config = {
        id: key,
        title,
        fix: true,
        checked: true,
        fixLeft,
        width,
      }
      return [...acc, config]
    }
    else {
      return acc
    }
  }, [])
}

const show = ref(false)
const checkAll = ref(false)

function showModal() {
  show.value = true
}

function closeModal() {
  show.value = false
}

async function handleSumbit(e: MouseEvent) {
  e.preventDefault()
  closeModal()

  const columns: any[] = [{
    type: 'selection',
    fixed: 'left',
    width: 50,
  }]

  const leftList = fixLeftList.value.map((item) => {
    return {
      title: item.title,
      key: item.id,
      fixed: 'left',
      width: item.width,
    }
  })

  const unfixList = onList.value.map((item) => {
    return {
      title: item.title,
      key: item.id,
      width: item.width,
    }
  })

  columns.push(...leftList, ...unfixList)
  emit('commit', columns)
}

defineExpose({
  showModal,
})

generatList()

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

function onCheckAllChange(value) {
  const ids: string[] = []

  for (const item of offList.value) {
    if (!item.fix) {
      item.checked = value
      ids.push(item.id)
    }
  }

  selectIds.value = value ? ids : []
}

function onCheckChange(checked: any, item: any) {
  const index = selectIds.value.indexOf(item.id)

  item.checked = checked

  if (index === -1 && checked)
    selectIds.value.push(item.id)
  else
    selectIds.value.splice(index, 1)
}

const showIds = computed(() => {
  return onList.value.map((item) => {
    return item.id
  })
})

watch(
  () => selectIds.value.length,
  (newVal, oldVal) => {
    if (newVal === oldVal)
      return

    const action = newVal > oldVal ? 'add' : 'remove'
    const diff: string[] = action === 'add' ? difference(selectIds.value, showIds.value) : difference(showIds.value, selectIds.value)

    if (diff.length === 0)
      return

    if (action === 'add') {
      for (const item of offList.value) {
        if (!item.fix && diff.includes(item.id)) {
          onList.value.push({
            id: item.id,
            title: item.title,
            fix: item.fix || false,
            width: item.width,
          })
        }
      }
    }
    else {
      const list = onList.value
      for (let index = 0; index < list.length; index++) {
        const item = list[index]
        if (!item.fix && diff.includes(item.id)) {
          list.splice(index, 1)
          index--
        }
      }
    }
  },
)

watch(
  () => showIds.value.length,
  (newVal, oldVal) => {
    if (newVal === oldVal)
      return

    const diff = difference(selectIds.value, showIds.value)

    if (diff.length === 0)
      return

    for (const item of offList.value) {
      if (!item.fix && diff.includes(item.id)) {
        const index = selectIds.value.indexOf(item.id)
        item.checked = false
        selectIds.value.splice(index, 1)
      }
    }
  },
)

function clearDragSource() {
  onList.value = onList.value.filter((item) => {
    return item.fix === true
  })
}

function removeHandler(id: string, type: 'fix' | 'unfix') {
  const list = type === 'fix' ? fixLeftList.value : onList.value

  const index = list.findIndex((item) => {
    return item.id === id
  })

  if (index !== -1)
    list.splice(index, 1)
}
</script>

<template>
  <n-modal v-model:show="show" transform-origin="center">
    <n-card class="cardstyle" :bordered="false" size="huge" role="dialog" aria-modal="true">
      <div class="wrapper">
        <span class="wrapper-title">自定义显示列</span>
        <div class="wrapper-bar">
          <div class="wrapper-info">
            <span :style="{ 'margin-left': '18px' }">字段信息</span>
          </div>
        </div>
        <n-grid cols="4" class="mt-4 proCard" responsive="screen" :x-gap="24">
          <n-grid-item span="3">
            <NCard
              :title="allCount" class="dragcardStyle" :segmented="{ content: true, footer: true }" size="small"
              :bordered="false"
            >
              <div>
                <n-input placeholder="搜索关键字">
                  <template #suffix>
                    <SvgIcon size="14px" name="magnifying-1" />
                  </template>
                </n-input>
                <div class="draggable-ul">
                  <div class="draggable-li">
                    <n-checkbox v-model:checked="checkAll" label="全部" @update:checked="onCheckAllChange" />
                  </div>
                  <div class="content">
                    <div
                      v-for="item in offList" :key="item.id" style="width: 170px;"
                      :class="{ 'disable-check': item.fix }" class="draggable-li"
                    >
                      <n-checkbox
                        v-model:checked="item.checked" :label="item.title" :disabled="item.fix"
                        @update:checked="onCheckChange($event, item)"
                      />
                    </div>
                  </div>
                </div>
              </div>
            </NCard>
          </n-grid-item>
          <n-grid-item>
            <NCard
              :title="selectCount" class="dragcardStyle" :segmented="{ content: true, footer: true }" size="small"
              :bordered="false"
            >
              <template #header-extra>
                <span class="textbtnStyle" @click="clearDragSource">清空</span>
              </template>
              <div>
                <n-input placeholder="搜索关键字">
                  <template #suffix>
                    <SvgIcon size="14px" name="magnifying-1" />
                  </template>
                </n-input>
                <div class="drag-wrapper">
                  <div>固定在左侧</div>
                  <VueDraggable v-model="fixLeftList" class="draggable-ul" :animation="150" group="show">
                    <div
                      v-for="item in fixLeftList" :key="item.id" :class="{ fix: item.fix }"
                      class="cursor-move draggable-item"
                    >
                      <span class="ml-2">{{ item.title }}</span>
                      <SvgIcon
                        v-if="!item.fix" size="16px" style="display: block; margin-left: auto; cursor: pointer"
                        name="clear" @click="removeHandler(item.id, 'fix')"
                      />
                    </div>
                  </VueDraggable>
                  <div>不固定</div>
                  <VueDraggable v-model="onList" class="draggable-ul" :animation="150" group="show">
                    <div
                      v-for="item in onList" :key="item.id" :class="{ fix: item.fix }"
                      class="cursor-move draggable-item"
                    >
                      <span class="ml-2">{{ item.title }}</span>
                      <SvgIcon
                        v-if="!item.fix" size="16px" style="display: block; margin-left: auto; cursor: pointer"
                        name="clear" @click="removeHandler(item.id, 'unfix')"
                      />
                    </div>
                  </VueDraggable>
                </div>
              </div>
            </NCard>
          </n-grid-item>
        </n-grid>
      </div>

      <template #footer>
        <div class="wrapper-footer">
          <n-button type="info" @click="handleSumbit">
            确认
          </n-button>
          <n-button secondary style="margin-left:15px" @click="closeModal">
            取消
          </n-button>
        </div>
      </template>
    </n-card>
  </n-modal>
</template>

<style lang="less" scoped>
.wrapper {
  display: flex;
  flex-direction: column;

  &-title {
    font-weight: bold;
    font-size: 16px;
  }

  &-bar {
    background-color: #e8e8e8;
    width: 100%;
    margin-top: 20px;
  }

  &-footer {
    display: flex;
    justify-content: flex-end;
  }

  &-info {
    font-weight: bold;
    position: relative;

    &:before {
      background-color: #1980ff;
      content: '';
      width: 5px;
      border-radius: 2px;
      top: 0;
      bottom: 0;
      position: absolute;
    }
  }
}

.dragcardStyle {
  --n-padding-bottom: 0px !important;
  --n-padding-left: 0px !important;
}

.cardstyle {
  width: 820px;
  --n-padding-bottom: 20px;
  --n-padding-left: 24px;
}

.textbtnStyle {
  cursor: pointer;
  color: #1980ff;
}

.drag-wrapper {
  border: 1px solid #cad2dd;
  color: gray;
  padding: 12px;
}

.draggable-ul {
  width: 100%;
  overflow: hidden;
  border-top: 0px;
  border-radius: 2px;
  display: block;

  .content {
    display: flex;
    flex-wrap: wrap;
  }

  .draggable-li {
    padding: 10px 16px;
    color: #333;
  }

  .draggable-item {
    padding: 10px 16px;
    color: #333;
    display: flex;
    align-items: center;
  }

  .disable-check {
    color: gainsboro;
  }
}

::v-deep(.n-card.n-card--content-segmented > .n-card__content:not(:first-child)) {
  border: 0px;
}

::v-deep(.n-card > .n-card-header) {
  --n-padding-top: 0px;
  --n-padding-bottom: 12px;
}
</style>
