<template>
  <a-cascader v-bind="filteredAttrs" v-model:value="innerValue" :options="options" :load-data="loadData"
    :placeholder="placeholder || '请选择'" :show-search="showSearch" :disabled="see || disabled" :size="size" :multiple="multiple"
    :change-on-select="false" :field-names="{ label: 'label', value: 'value', children: 'children' }"
    @change="handleChange" :show-checked-strategy="showCheckedStrategy" @dropdown-visible-change="handleDropdown" :style="style" />
</template>

<script>
import { Cascader } from 'ant-design-vue'

export default {
  name: 'OrgPathSelector',
  inheritAttrs: false,
  components: { [Cascader.name]: Cascader },
  computed: {
    see() {
      return this.$store?.forms?.see || false;
    }
  },
  props: {
    modelValue: [String, Number, Array],
    selectionType: {
      type: String,
      default: 'user',
      validator: v => ['org', 'dept', 'user'].includes(v),
    },
    showSearch: { type: Boolean, default: true },
    disabled: Boolean,
    size: { type: String, default: 'middle' },
    multiple: { type: Boolean, default: false },
    placeholder: String,
    style: { type: [String, Object], default: "width: 100%;" },
  },

  data() {
    return {
      innerValue: [],
      options: [],
      cache: new Map(),
      showCheckedStrategy: Cascader.SHOW_CHILD,
      firstLevelLoaded: false,
      isInternalUpdate: false,
    }
  },

  mounted() {
    if (this.modelValue) {
      this.restoreValue(this.modelValue)
    }
  },

  watch: {
    modelValue(val) {
      if (this.isInternalUpdate) {
        this.isInternalUpdate = false
        return
      }
      if (val) this.restoreValue(val)
      else this.reset()
    },
    selectionType() {
      this.reset()
      if (this.modelValue) {
        this.restoreValue(this.modelValue)
      }
    },
  },

  computed: {
    filteredAttrs() {
      const attrs = { ...this.$attrs }
      Object.keys(attrs).forEach(k => {
        if (k.startsWith('on') || k.startsWith('@')) delete attrs[k]
      })
      return attrs
    },
  },

  methods: {
    /* ================= 基础规则 ================= */

    getMaxLevel() {
      if (this.selectionType === 'org') return 1
      if (this.selectionType === 'dept') return 2
      return 3
    },

    isLeaf(level) {
      return level === this.getMaxLevel() - 1
    },

    /* ================= normalize ================= */

    normalize(list = [], level = 0) {
      return list.map(n => ({
        value: String(n.value),
        label: n.label,
        isLeaf: this.isLeaf(level),
        children: undefined,
        type: ['org', 'dept', 'user'][level],
      }))
    },

    normalizePath(list = [], level = 0) {
      return list.map(n => ({
        value: String(n.value),
        label: n.label,
        isLeaf: this.isLeaf(level),
        type: ['org', 'dept', 'user'][level],
        children: Array.isArray(n.children)
          ? this.normalizePath(n.children, level + 1)
          : undefined,
      }))
    },

    extractPath(tree) {
      const path = []
      let node = tree?.[0]
      while (node) {
        path.push(node.value)
        node = node.children?.[0]
      }
      return path
    },

    /* ================= 关键：深度合并路径树 ================= */

    mergePathTree(target = [], source = []) {
      source.forEach(src => {
        let tgt = target.find(t => t.value === src.value)
        if (!tgt) {
          tgt = { ...src }
          target.push(tgt)
        }
        if (src.children?.length) {
          if (!tgt.children) tgt.children = []
          this.mergePathTree(tgt.children, src.children)
        }
      })
      return target
    },

    /* ================= 值返显 ================= */

    restoreValue(val) {
      if (this.multiple) {
        const values = Array.isArray(val)
          ? val.map(String)
          : String(val).split(',').filter(Boolean)
        this.loadMultiplePaths(values)
      } else {
        this.loadSinglePath(String(val))
      }
    },

    async loadSinglePath(id) {
      try {
        this.isInternalUpdate = true
        const res = await this.$get('/system/organization/getOrgPathSelect', {
          id,
          level: this.selectionType,
        })
        if (res.data?.code !== 200) return

        const tree = this.normalizePath(res.data.data || [], 0)
        this.options = this.mergePathTree(this.options, tree)
        this.innerValue = this.extractPath(tree)
      } finally {
        this.$nextTick(() => (this.isInternalUpdate = false))
      }
    },

    async loadMultiplePaths(values) {
      try {
        this.isInternalUpdate = true
        this.innerValue = []

        const trees = await Promise.all(
          values.map(v =>
            this.$get('/system/organization/getOrgPathSelect', {
              id: v,
              level: this.selectionType,
            }).then(res =>
              res.data?.code === 200
                ? this.normalizePath(res.data.data || [], 0)
                : null
            )
          )
        )

        trees.forEach(tree => {
          if (!tree) return
          this.options = this.mergePathTree(this.options, tree)
          const path = this.extractPath(tree)
          if (path.length) this.innerValue.push(path)
        })
      } finally {
        this.$nextTick(() => (this.isInternalUpdate = false))
      }
    },

    /* ================= 下拉 & 懒加载 ================= */

    async handleDropdown(visible) {
      if (!visible || this.firstLevelLoaded) return
      const list = await this.fetchList(null, 0)
      this.options = this.mergePathTree(this.options, this.normalize(list, 0))
      this.firstLevelLoaded = true
    },

    async loadData(selectedOptions) {
      const target = selectedOptions[selectedOptions.length - 1]
      const level = selectedOptions.length - 1
      if (target.isLeaf) return

      const key = `${target.value}_${level}`
      if (this.cache.has(key)) {
        target.children = this.cache.get(key)
        return
      }

      const raw = await this.fetchList(target.value, level + 1)
      const normalized = this.normalize(raw, level + 1)
      target.children = normalized
      this.cache.set(key, normalized)
    },

    async fetchList(parentId, level) {
      let api = ''
      const vars = {}
      if (level === 0) api = '/system/organization/list'
      else if (level === 1 && this.selectionType !== 'org') {
        api = '/system/sysdept/list'
        vars.org_id = parentId
      } else if (level === 2 && this.selectionType === 'user') {
        api = '/system/sysusers/list'
        vars.dept_id = parentId
      }
      if (!api) return []

      const res = await this.$post(api, {
        page: { current: 1, size: 1000 },
        vars,
      })
      return res.data?.data?.rows || []
    },

    /* ================= change 处理（关键） ================= */

    handleChange(paths, selectedOptions) {
      let finalValue

      if (this.multiple) {
        // 永远从 selectedOptions 里拿叶子节点
        const leafIds = selectedOptions
          .flat()
          .filter(o => o.isLeaf)
          .map(o => o.value)

        finalValue = leafIds.join(',')
      } else {
        finalValue = Array.isArray(paths)
          ? paths[paths.length - 1]
          : paths ?? null
      }

      this.isInternalUpdate = true
      this.$emit('update:modelValue', finalValue)
      this.$emit('change', finalValue, selectedOptions, paths)
    },

    reset() {
      this.innerValue = []
      this.options = []
      this.cache.clear()
      this.firstLevelLoaded = false
      this.isInternalUpdate = false
    },
  },
}
</script>

<style scoped>
.entity-selector {
  width: 100%;
}
</style>
