<template>
  <el-input
    ref="baseInputRef"
    v-bind="props"
    v-model="baseData.search"
    class="base-input-search"
    style="width: 100%"
    clearable
    @blur="blurEvent"
    @input="inputEvent"
    @keydown.enter.stop.prevent="$throttle(handleEnterEvent, $event)"
    @clear="$throttle(handleSearchSubmit)"
  >
    <template v-if="$slots.prefix" #prefix>
      <slot name="prefix"></slot>
    </template>
    <template v-if="$slots.suffix" #suffix>
      <slot name="suffix"></slot>
    </template>
    <template v-if="$slots.prepend" #prepend>
      <slot name="prepend"></slot>
    </template>
    <template #append>
      <slot name="append">
        <el-button
          class="search-butt"
          :disabled="disabled"
          :loading="loading"
          v-bind="{ tabindex }"
          :icon="IconSolarMagniferLinear"
          style="max-width: 62px"
          @click="$throttle(handleButtonEvent, $event)"
        ></el-button>
      </slot>
    </template>
  </el-input>
</template>

<script setup lang="ts">
  import type { InputProps } from 'element-plus';
  import IconSolarMagniferLinear from '~icons/solar/magnifer-linear';

  export type MergedInputProps = InputProps & {
    /** 加载状态 (是否正在搜索中) */
    loading?: boolean;
    /** 搜索值为空时是否禁止搜索 */
    forbidEmptySearch?: boolean;
    /** 绑定值 */
    modelValue?: string;
    /** 是否禁用 */
    disabled?: boolean;
    /** 输入框的 tabindex */
    tabindex?: number;
  };

  const props = withDefaults(defineProps<MergedInputProps>(), {
    modelValue: '',
    tabindex: undefined,
  });

  defineSlots<{
    /** 输入框头部内容 (输入框里面)，只对非 type="textarea" 有效 */
    prefix: () => any;
    /** 输入框尾部内容 (输入框里面)，只对非 type="textarea" 有效 */
    suffix?: () => any;
    /** 输入框前置内容 (输入框外面)，只对非 type="textarea" 有效 */
    prepend?: () => any;
    /** 输入框后置内容 (输入框外面)，只对非 type="textarea" 有效 */
    append?: () => any;
  }>();

  const emit = defineEmits<{
    (e: 'update:modelValue', val: number | string): void;
    (e: 'submit', search: number | string, event: HTMLElement): void;
    (e: 'enter', search: number | string, event: HTMLElement): void;
    (e: 'input', value: number | string, original: number | string): void;
    (e: 'blur', event: FocusEvent): void;
  }>();

  const baseData = shallowReactive({
    search: props.modelValue,
  });
  watchEffect(() => {
    baseData.search = props.modelValue;
  });
  watchEffect(() => {
    emit('update:modelValue', baseData.search);
  });

  /**
   * 点击搜索按钮
   */
  function handleButtonEvent(event: MouseEvent) {
    const dom = (event.currentTarget as HTMLElement).parentNode?.parentNode;
    dom && handleSearchSubmit(dom as HTMLElement);
  }

  /**
   * 点击回车键
   */
  function handleEnterEvent(event: KeyboardEvent) {
    const dom = (event.currentTarget as HTMLElement).parentNode;
    if (dom) {
      emit('enter', baseData.search, dom as HTMLElement);
      handleSearchSubmit(dom as HTMLElement);
    }
  }

  /**
   * elDom 代表el-input的元素 主要用于弹出框等(不用可忽略)
   */
  function handleSearchSubmit(elDom: HTMLElement) {
    if (!props.forbidEmptySearch || baseData.search) {
      nextTick(() => {
        emit('submit', baseData.search, elDom);
      });
    }
  }

  /**
   * 输入改变时触发
   */
  function inputEvent(value: number | string) {
    nextTick(() => {
      emit('input', baseData.search, value);
    });
  }

  /**
   * 失去焦点时触发
   */
  function blurEvent(event: FocusEvent) {
    emit('blur', event);
  }

  const baseInputRef: $RefComp<'ElInput'> = ref(null);

  defineExpose({
    /** 搜索框聚焦 */
    focus: () => {
      baseInputRef.value && baseInputRef.value?.focus && baseInputRef.value.focus();
    },
  });
</script>
