<script setup lang="ts">
import type { AxiosRequestConfig } from "axios"
import Rs from "@/core/services/RequestService"
export interface SelectOptionProp {
  key: string | number
  value: string | number
  label?: string | number //若不设置则默认与value相同
  disabled?: boolean
}
export interface SelectProp {
  value: string | number | Array<string> | Array<number>
  name?: string
  url?: string
  method?: string
  configs?: AxiosRequestConfig
  formatFunction?: (data: any) => SelectOptionProp
  staticOptions?: Array<SelectOptionProp>
  data?: Array<any>
  placeholder?: string
  disabled?: boolean
  isSearch?: boolean
  autocomplete?: string
  size?: "large" | "default" | "small" //输入框尺寸
  effect?: "dark " | "light" //Tooltip 主题，内置了 dark / light 两种
  clearable?: boolean //是否可以清空选项
  clearIcon?: string //是否可以清空选项
  multiple?: boolean //是否多选
  multipleLimit?: number //为0时不限制
  placement?:
    | "top"
    | "top-start"
    | "top-end"
    | "bottom"
    | "bottom-start"
    | "bottom-end"
    | "left"
    | "left-start"
    | "left-end"
    | "right"
    | "right-start"
    | "right-end" //下拉框出现的位置
  filterable?: boolean //Select 组件是否可筛选
  filterMethod?: (v: string, o: Array<SelectOptionProp>) => any //自定义筛选方法
  remote?: boolean //其中的选项是否从服务器远程加载
  remoteShowSuffix?: boolean //远程搜索方法显示后缀图标
  remoteMethod?: (v: string, o: Array<SelectOptionProp>) => any //远程搜索方法显示后缀图标
  formatRemoteData?: (v: any) => any
  loading?: boolean //是否正在从远程获取数据
  loadingText?: string //从服务器加载内容时显示的文本
  noMatchText?: string //搜索条件无匹配时显示的文字，也可以使用 empty 插槽设置
  noDataText?: string //搜索条件无匹配时显示的文字，也可以使用 empty 插槽设置
  popperClass?: string //选择器下拉菜单的自定义类名
  suffixIcon?: string //后缀图标组件
  reserveKeyword?: boolean //当 multiple 和 filter被设置为 true 时，是否在选中一个选项后保留当前的搜索关键词
  defaultFirstOption?: boolean //是否在输入框按下回车时，选择第一个匹配项。 需配合 filterable 或 remote 使用
  popperAppendToBody?: boolean //是否将弹出框插入至 body 元素 当弹出框的位置出现问题时，你可以尝试将该属性设置为false
  teleported?: boolean //该下拉菜单是否使用teleport插入body元素
  persistent?: boolean //当下拉选择器未被激活并且persistent设置为false，选择器会被删除。
  automatiDropdown?: boolean //对于不可过滤的 Select 组件，此属性决定是否在输入框获得焦点后自动弹出选项菜单
  fitInputWidth?: boolean //下拉框的宽度是否与输入框相同
  validateEvent?: boolean //是否触发表单验证
}
const props = withDefaults(defineProps<SelectProp>(), {
  value: "",
  url: "",
  method: "get",
  configs: undefined,
  multiple: false,
  multipleLimit: 0,
  filterable: false,
  remote: false,
  formatRemoteData: (v: any) => {
    return v
  },
  loading: false,
  loadingText: "加载中...",
  noMatchText: "没有匹配项",
  noDataText: "未查询到数据",
  isSearch: false,
  disabled: false,
  clearable: false,
  clearIcon: "CircleClose",
  effect: "light",
  size: "default",
  placement: "bottom-start",
  autocomplete: "off",
  placeholder: "请选择",
  popperClass: "",
  suffixIcon: "ArrowDown",
  defaultFirstOption: false,
  reserveKeyword: true,
  popperAppendToBody: true,
  teleported: true,
  persistent: true,
  automatiDropdown: false,
  fitInputWidth: false,
  validateEvent: false,
})
const emits = defineEmits<{
  (e: "update:value", v: string | number | Array<string> | Array<number>): void
  (e: "change", v: string | number | Array<string> | Array<number>): void
  (e: "visible-change", v: boolean): void //下拉框出现/隐藏时触发 出现则为 true，隐藏则为 false
  (e: "remove-tag", v: string | number | Array<string> | Array<number>): void
  (e: "clear"): void
  (e: "blur", v: FocusEvent): void
  (e: "focus", v: FocusEvent): void
}>()
const { value, url } = toRefs(props)
const loading = ref(props.loading)
const remote = ref(props.remote)
const filterable = ref(props.filterable)
const _staticOptions = ref<Array<SelectOptionProp>>()
const options = ref<Array<SelectOptionProp>>(_staticOptions.value ?? [])

let remoteFunction: (v: string) => void

function init() {
  _staticOptions.value = Object.assign([], props.staticOptions || [], formatSelectData(props.data) ?? [])
  if (props.remoteMethod) {
    filterable.value = true
    remote.value = true
    remoteFunction = (v: string) => {
      props.remoteMethod && props.remoteMethod(v, options.value)
      loading.value = false
    }
  } else if (props.url) {
    filterable.value = true
    remote.value = true
    const configs = Object.assign({}, { url: url.value, method: props.method, successAlert: false }, props.configs)

    remoteFunction = (query: string) => {
      options.value = Object.assign([], _staticOptions.value ?? [])
      console.log("======>", options.value, "=", _staticOptions.value)

      if (!props.isSearch || query) {
        loading.value = true
        Rs.request(configs).then((res: any) => {
          processData(res.data)
        })
        // if (props.method.toLowerCase() == "get") {
        //   Rs.get(configs).then((res: any) => {
        //     processData(res.data)
        //   })
        // } else if (props.method.toLowerCase() == "post") {
        //   Rs.get(configs).then((res: any) => {
        //     processData(res.data)
        //   })
        // }
      }
      function processData(data: any) {
        let result = formatSelectData(data)
        if (query) {
          result = result.filter((v: SelectOptionProp) => {
            return (
              (v.label as string).toLowerCase().includes(query.toLowerCase()) ||
              (v.value as string).toLowerCase().includes(query.toLowerCase())
            )
          })
        }
        options.value.push(...result)
        loading.value = false
      }
    }
  }
}

function formatSelectData(v: any) {
  const result: Array<SelectOptionProp> = []
  const data = props.formatRemoteData && typeof props.formatRemoteData == "function" ? props.formatRemoteData(v) : v
  if (data && data.length) {
    data.forEach((v: any) => {
      let item = {} as SelectOptionProp
      if (props.formatFunction) {
        item = props.formatFunction(v)
      } else {
        item = Object.assign({}, v)
        if ("value" in v) {
          item.key = v.value + ""
          item.value = v.value + ""
        } else if ("code" in v) {
          item.key = v.code + ""
          item.value = v.code + ""
        }
        if ("label" in v) {
          item.label = v.label + ""
        } else if ("name" in v) {
          item.label = v.name + ""
        } else if ("title" in v) {
          item.label = v.title + ""
        }
      }
      result.push(item)
    })
  }

  return result
}
function onChange(val: string | number | Array<string> | Array<number>) {
  emits("update:value", val)
  emits("change", val)
}
function onRemoveTag(val: string | number | Array<string> | Array<number>) {
  emits("remove-tag", val)
}
function onVisibleChange(val: boolean) {
  //下拉框出现/隐藏时触发 出现则为 true，隐藏则为 false
  emits("visible-change", val)
}
function onBlur(v: FocusEvent) {
  emits("blur", v)
}
function onFocus(v: FocusEvent) {
  emits("focus", v)
}
function onClear() {
  emits("clear")
}
onMounted(() => {
  init()
})
</script>
<template>
  <el-select
    v-model="value"
    :placeholder="placeholder"
    :disabled="disabled"
    :multiple="multiple"
    :multiple-limit="multipleLimit"
    :clearable="clearable"
    :clear-icon="clearIcon"
    :suffix-icon="suffixIcon"
    :popper-class="popperClass"
    :autocomplete="autocomplete"
    :size="size"
    :effect="effect"
    :placement="placement"
    :filterable="filterable"
    :remote="remote"
    :remote-method="remoteFunction"
    :remote-show-suffix="remoteShowSuffix"
    :loading="loading"
    :loading-text="loadingText"
    :no-match-text="noMatchText"
    :no-data-text="noDataText"
    :default-first-option="defaultFirstOption"
    :popper-append-to-body="popperAppendToBody"
    :reserve-keyword="reserveKeyword"
    :teleported="teleported"
    :persistent="persistent"
    :automati-dropdown="automatiDropdown"
    :fit-input-width="fitInputWidth"
    :validate-event="validateEvent"
    @change="onChange"
    @remove-tag="onRemoveTag"
    @visible-change="onVisibleChange"
    @blur="onBlur"
    @focus="onFocus"
    @clear="onClear"
  >
    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
  </el-select>
</template>
