<template>
  <div v-if="showDisplayValue" class="display-value" @click="handleDisplayValueClick">
    <span>{{displayValue}}</span>
  </div>
  <a-tree-select
    v-else
    ref="selectRef"
    style="min-width: 150px"
    :defaultOpen="true"
    :value="valueV"
    :dropdown-style="dropdownStyle"
    :notFoundContent="notFoundContent"
    :tree-data="treeData"
    :load-data="handleLoadData"
    :treeDataSimpleMode="true"
    :placeholder="placeholder"
    :allow-clear="allowClear"
    :multiple="multiple"
    v-bind="customProps"
    @blur="handleSelectBlur"
    @update:value="handleChange"
  />
</template>

<script lang="ts">
import { TreeDataItem } from "@/models/ui/TreeCommon";
import { SelectProps } from "ant-design-vue";
import { defineComponent, PropType } from "vue";

export type LoadDataFun = (pid: string|number, level: number) => Promise<TreeDataItem[]>;
export type CheckClickableFun = (item: TreeDataItem) => Promise<boolean>;

export type GetDiaplayValue = (ref: IdAsValueTreeDropdownInterface) => string;
export type GetRef = (ref: IdAsValueTreeDropdownInterface) => void;

/**
 * IdAsValueTreeDropdown 的公共接口
 */
export interface IdAsValueTreeDropdownInterface {
  /**
   * 获取某个ID的树(正排列)
   * @param value 要获取的ID
   */
  getTree(value: number) : Array<TreeDataItem>;
  /**
   * 获取某个ID的Lablel
   * @param value 要获取的ID
   */
  getLableByValue(value: number) : string;
  /**
   * 重新加载数据
   */
  reload(): void;
}
/**
 * IdAsValueTreeDropdown 的公共接口
 */
export interface IdAsValueTreeDropdownProps {
  /**
   * 允许清除
   */
  allowClear?: boolean,
  /**
   * 多选？
   */
  multiple?: boolean,
  dropdownStyle?: Record<string, unknown>,
  disabled?: boolean,
  placeholder?: string,
  /**
   * 未找到数据时的文案
   */
  notFoundContent?: string,
  /**
   * 初始化时加载数据
   */
  loadAtStart?: boolean,
  /**
   * 加载数据
   */
  loadData?: LoadDataFun,
  /**
   * 自定义检查条目是否可点击回调
   */
  checkClickable?: CheckClickableFun,
  /**
   * 获取显示数据回调
   */
  getDisplayValue?: GetDiaplayValue,
  /**
   * 是否在非激活时显示临时字符串（防止树形数据没有加载，而无法显示当前值）
   */
  showDisplayValueBeforeEdit?: boolean,
  /**
   * 子数据最大层级
   */
  maxLevel?: number,
  /**
   * 是否只有最后一级可以点击
   */
  onlyLastLevelClickable?: boolean,
  /**
   * a-select 其他自定义参数
   */
  customProps?: SelectProps,
}

/**
 * 使用数据的ID作为value的下拉框包装
 */
export default defineComponent({
  name: "IdAsValueTreeDropdown",
  emits: [
    'update:value',
    'change',
    'blur',
  ],
  props: {
    allowClear: {
      default: true,
      type: Boolean
    },
    multiple: {
      default: false,
      type: Boolean
    },
    dropdownStyle: {
      type: Object,
      default: () => { return { maxHeight: '400px', overflow: 'auto' } }
    },
    disabled: {
      default: false,
      type: Boolean
    },
    placeholder: {
      default: '请选择，输入可进行搜索',
      type: String
    },
    notFoundContent: {
      default: '未找到数据，请换个搜索词再试',
      type: String
    },
    loadAtStart: {
      default: true,
      type: Boolean
    },
    value: {
      default: null,
    },
    loadData: {
      type: Function as PropType<LoadDataFun>,
      default: null,
    },
    checkClickable: {
      type: Function as PropType<CheckClickableFun>,
      default: null,
    },
    getDisplayValue: {
      type: Function as PropType<GetDiaplayValue>,
      default: null,
    },
    defaultDisplayValue: {
      type: String,
      default: '',
    },
    showDisplayValueBeforeEdit: {
      default: false,
      type: Boolean
    },
    maxLevel: {
      default: 0,
      type: Number,
    },
    onlyLastLevelClickable: {
      default: false,
      type: Boolean
    },
    /**
     * a-select 其他自定义参数
     */
    customProps: {
      type: Object as PropType<SelectProps>,
      default: null,
    },
  },
  computed: {
    displayValue() : string {
      if (this.valueV != null && this.valueV != 0 && this.defaultDisplayValue != '')
        return this.defaultDisplayValue;
      if (this.getDisplayValue)
        return (this.getDisplayValue as GetDiaplayValue)(this as IdAsValueTreeDropdownInterface); 
      return '';
    },
  },
  methods: {
    handleChange(value: unknown) {
      this.$nextTick(() => {
        if(value != this.value) {
          this.$emit('update:value', value); 
          this.$emit('change', value); 
        }
      })
    },
    handleLoadData(treeNode: { dataRef: TreeDataItem }) {
      return new Promise((resolve: (value?: unknown) => void) => {
        const { id, level } = treeNode.dataRef;
        this.doLoadData(id, level as number).then(() => resolve()).catch(() => resolve());
      });
    },
    handleDisplayValueClick() {
      this.showDisplayValue = false;
      setTimeout(() => {
        (this.$refs.selectRef as {
          focus: () => void
        }).focus();
      }, 200);
    },
    handleSelectBlur() {
      if(this.showDisplayValueBeforeEdit) {
        if(this.valueV != null && this.valueV != 0 && this.defaultDisplayValue != '')
          this.showDisplayValue = true;
        else if (this.getLableByValue(this.valueV as number) === '') //只有没有在列表中搜索到数据时，才显示临时数据
          this.showDisplayValue = true;
      }
    },
    doLoadData(pid: string|number|null, level: number) {
      const loadData = this.loadData;
      if(typeof loadData === 'function') {
        return (loadData as LoadDataFun)(pid as string, level).then((d) => {
          for(let i = this.treeData.length - 1; i >= 0; i--)
            if(this.treeData[i].pId == pid)
              this.treeData.splice(i, 1);
          d.forEach(h => {
            h.level = level + 1;
            if(this.maxLevel > 0 && h.level >= this.maxLevel)
              h.isLeaf = true;
            if(typeof this.checkClickable === 'function')
              this.checkClickable(h).then((v: boolean) => h.selectable = v);
            else if(this.maxLevel > 0) { 
              if(h.level >= this.maxLevel)
                h.selectable = false;
              if(this.onlyLastLevelClickable) 
                h.selectable = (h.level == this.maxLevel);
            }
            this.treeData.push(h)
          });
        });
      } else 
        return Promise.resolve();
    },

    /**
     * 获取某个ID的树(正排列)
     */
    getTree(value: number) {
      const result = new Array<TreeDataItem>();
      let child : TreeDataItem|null = this.treeData.find((v) => v.id == value) as TreeDataItem;
      while(child) {
        result.unshift(child);
        if(child.pId == 0) child = null;
        else child = this.treeData.find((v) => v.id == (child as TreeDataItem).pId) as TreeDataItem;
      }
      return result;
    },
    /**
     * 获取某个ID的Lablel
     */
    getLableByValue(value: number) {
      const data = this.treeData;
      for (let i = 0; i < data.length; i++) {
        if(data[i].value == value) {
          return data[i].title;
        }
      }
      return '';
    },
    /**
     * 重新加载数据
     */
    reload() {
      this.treeData = [];
      this.doLoadData(0, 0) 
    },
  },
  watch: {
    value(v) {
      this.valueV = v;
    },
    showDisplayValueBeforeEdit(v, old) {
      if(!old && v) {
        this.showDisplayValue = true;
      }
    },
  },
  data() {
    return {
      showDisplayValue: false,
      valueV: null as null|number|string,
      treeData: [] as TreeDataItem[],
    }
  },
  mounted() { 
    this.valueV = this.value;
    if(this.showDisplayValueBeforeEdit)
      this.showDisplayValue = true;
    setTimeout(() => { 
      if(this.loadAtStart) {
        this.treeData = [];
        this.doLoadData(0, 0) ;
      }
    } , 300);
  }
});
</script>

<style lang="scss" scoped>
.display-value {
  min-width: 150px;
  padding: 4px 11px;
  color: rgba(0, 0, 0, 0.85);
  font-size: 14px;
  line-height: 1.5715;
  background-color: #fff;
  background-image: none;
  border: 1px solid #d9d9d9;
  border-radius: 2px;
}
//暗黑主题
body[data-theme="dark"] {
  .display-value {
    color: #dedede;
    background-color: #1f1f1f;
    border: 1px solid #434343;
  }
}
</style>