<template>
  <el-dialog
    :model-value="visible"
    title="选择人员"
    :width="600"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :destroy-on-close="true"
    :append-to-body="true"
    @open="onOpen"
    @close="onClose"
  >
    <div class="selector">
      <div class="selector-left">
        <cacp-autocomplete
          v-model="selectedKeys"
          :multiple="multiple"
          value-key="fullPathName"
          :fetch-suggestions="querySearch"
          clearable
          placeholder="请输入关键字"
          @select="onSelect"
        ></cacp-autocomplete>
        <div class="selector-tree">
          <el-scrollbar>
            <el-tree
              ref="selectorTreeRef"
              :props="treeProps"
              node-key="fullPathName"
              :show-checkbox="true"
              :check-strictly="true"
              :default-checked-keys="selectedKeys"
              :load="onLazyLoad"
              lazy
              @check-change="onCheckChange"
              class="cacp-pd-s"
            >
              <template #default="{ data }">
                <template v-if="data.oguType === 'ORGANIZATION'">
                  <el-icon class="cacp-mr-s" :size="16">
                    <Grid />
                  </el-icon>
                  <span>{{ data.oguName }}</span>
                </template>
                <template v-else-if="data.oguType === 'USER'">
                  <el-icon v-if="data.sideline" class="cacp-mr-s" :size="16" title="兼职">
                    <User />
                  </el-icon>
                  <el-icon v-else class="cacp-mr-s" :size="16" title="主职">
                    <UserFilled />
                  </el-icon>
                  <span>{{ data.oguName }}</span>
                </template>
              </template>
            </el-tree>
          </el-scrollbar>
        </div>
      </div>
      <div class="selector-right">
        <div class="selector-toolbar">
          <span class="count">已选 {{ count }} 个</span><el-link type="primary" @click.prevent="onClear">清空</el-link>
        </div>
        <div class="selector-list">
          <selector-list :dataList="selectedList" @on-delete="onRemove"></selector-list>
        </div>
      </div>
    </div>
    <template #footer>
      <el-button @click="onClose">取消</el-button>
      <el-button type="primary" @click="onSave">确定</el-button>
    </template>
  </el-dialog>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { ElTree } from 'element-plus'
import type TreeNode from 'element-plus/es/components/tree/src/model/node'
import { cloneDeep } from 'lodash-es'
import * as apis from '@/apis/auth'
import SelectorList from './SelectorList.vue'
import type { BaseCacpOgu, CacpUser } from '@cacp/ui'
import { SuccessResultCode } from '@cacp/ui'
type TreeNodeDataType = BaseCacpOgu & { disabled: boolean; isLeaf: boolean }
const selectorTreeRef = ref<InstanceType<typeof ElTree>>()
const props = withDefaults(
  defineProps<{
    visible: boolean
    multiple?: boolean
    value?: Array<CacpUser>
    rootPath?: string
  }>(),
  {
    visible: false,
    multiple: false,
    value: () => [],
    rootPath: ''
  }
)
const emits = defineEmits<{
  (e: 'on-close'): void
  (e: 'on-save', value: Array<CacpUser>): void
}>()
const treeProps = {
  label: 'oguName',
  isLeaf: 'isLeaf'
}
const rootDeptPath = ref<string>(props.rootPath ?? '')
const cachedList = ref<Array<CacpUser>>([])
const selectedKeys = ref<Array<string>>([])
const selectedList = computed<Array<CacpUser>>(() => {
  return cachedList.value.filter((o) => selectedKeys.value.includes(o.fullPathName))
})
const count = computed<number>(() => {
  return selectedKeys.value.length
})

async function onOpen() {
  selectedKeys.value = props.value ? props.value.map((o) => o.fullPathName) : []
  cachedList.value = props.value ? cloneDeep(props.value) : []
}
function onClose(): void {
  emits('on-close')
}
function onSave(): void {
  emits('on-save', selectedList.value)
}
async function onLazyLoad(
  node: TreeNode,
  resolve: (data: Array<TreeNodeDataType>) => void,
  reject: () => void
): Promise<void> {
  if (node.level === 0) {
    let root: TreeNodeDataType
    if (props.rootPath) {
      const result = await apis.getOrganizationByPath(props.rootPath)
      if (result.code === SuccessResultCode && result.data) {
        root = Object.assign({}, result.data, { disabled: true, isLeaf: false })
        rootDeptPath.value = root.fullPathName
        resolve([root])
      } else {
        if (reject) {
          reject()
        }
      }
    } else {
      const result = await apis.getRootOrganization()
      if (result.code === SuccessResultCode && result.data) {
        root = Object.assign({}, result.data, { disabled: true, isLeaf: false })
        rootDeptPath.value = root.fullPathName
        resolve([root])
      } else {
        if (reject) {
          reject()
        }
      }
    }
    return
  }
  const parent = node.data
  const resOrg = await apis.getOrganizationListByParent(parent.fullPathName, true)
  if (resOrg.code !== SuccessResultCode) {
    reject()
    return
  }
  const resUser = await apis.getUserListByParent(parent.fullPathName, true)
  if (resUser.code !== SuccessResultCode) {
    if (reject) {
      reject()
    }
    return
  }
  const orgData = resOrg.data?.map((o) => {
    return Object.assign({}, o, { disabled: true, isLeaf: false })
  })
  const userData = resUser.data?.map((o) => {
    return Object.assign({}, o, { disabled: false, isLeaf: true })
  })
  const children: Array<TreeNodeDataType> = [...(orgData ?? []), ...(userData ?? [])]
  resolve(children)
}
function onCheckChange(data: TreeNodeDataType, checked: boolean) {
  if (checked) {
    const user: CacpUser = Object.fromEntries(
      Object.entries(data)
        .filter(([k, v]: [string, any]) => k !== 'isLeaf' && k !== 'disabled')
        .map(([k, v]: [string, any]) => {
          return [k, v]
        })
    ) as CacpUser
    handleCachedList([user])
    if (!props.multiple) {
      selectedKeys.value.splice(0, 1, data.fullPathName)
    } else {
      if (!selectedKeys.value.includes(data.fullPathName)) {
        selectedKeys.value.push(data.fullPathName)
      }
    }
  } else {
    const idx = selectedKeys.value.indexOf(data.fullPathName)
    if (idx > -1) {
      selectedKeys.value.splice(idx, 1)
    }
  }
  handleCheckStatus()
}
function onRemove(fullPathName: string): void {
  const idx = selectedKeys.value.indexOf(fullPathName)
  if (idx > -1) {
    selectedKeys.value.splice(idx, 1)
  }
  handleCheckStatus()
}

function onClear(): void {
  selectedKeys.value = []
  handleCheckStatus()
}

function handleCachedList(list: Array<CacpUser>): void {
  for (const org of list) {
    const idx = cachedList.value.findIndex((o) => o.fullPathName === org.fullPathName)
    if (idx > -1) {
      cachedList.value.splice(idx, 1)
    }
    cachedList.value.push(org)
  }
}
function handleCheckStatus(): void {
  if (selectorTreeRef.value) {
    selectorTreeRef.value.setCheckedKeys(selectedKeys.value, false)
  }
}
async function querySearch(query: string, cb: any) {
  if (query !== '') {
    const res = await apis.queryUserListByCondition(rootDeptPath.value, query)
    if (res.code === SuccessResultCode) {
      cb(res.data ?? [])
    }
  }
}

function onSelect(data: CacpUser, checked: boolean) {
  if (checked) {
    handleCachedList([data])
    if (!props.multiple) {
      selectedKeys.value.splice(0, 1, data.fullPathName)
    } else {
      if (!selectedKeys.value.includes(data.fullPathName)) {
        selectedKeys.value.push(data.fullPathName)
      }
    }
  } else {
    const idx = selectedKeys.value.indexOf(data.fullPathName)
    if (idx > -1) {
      selectedKeys.value.splice(idx, 1)
    }
  }
  handleCheckStatus()
}
</script>
<style lang="less" scoped>
.selector {
  display: flex;
  align-items: flex-start;
  border: 1px solid var(--el-border-color);
  border-radius: var(--el-border-radius-base);
  min-height: 260px;
  max-height: 400px;
  align-items: stretch;
  &-left {
    width: 280px;
    border-right: 1px solid var(--el-border-color);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    :deep(.el-input-group__append),
    :deep(.el-input__wrapper) {
      box-shadow: none;
      border-radius: 0;
    }
    // :deep(.el-input__wrapper) {
    //   padding-right: 0;
    // }
    :deep(.el-input) {
      height: 32px;
      border-bottom: 1px solid var(--el-input-border-color);
    }
  }
  &-search {
    line-height: 32px;
  }
  &-tree {
    flex: 1;
    overflow: hidden;
  }
  &-middle {
    width: 320px;
    border-right: 1px solid var(--el-border-color);
  }

  &-right {
    flex: 1;
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }
  &-list {
    flex: 1;
  }
  &-toolbar {
    line-height: 32px;
    height: 32px;
    padding: 0 var(--cacp-padding-space-s);
    font-size: var(--font-size-s);
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--el-border-color);
    justify-content: space-between;
  }
}
</style>
