<template>
  <a-select
    :class="['text-left', style && Object.keys(style).length > 0 ? 'customStyle' : '']"
    :style="style && Object.keys(style).length > 0 ? {} : { width: width }"
    v-model:value="selectValue"
    :placeholder="placeholder"
    :disabled="disabled"
    :readonly="readonly"
    :show-search="showSearch"
    @change="handleSelectChange"
    :options="options"
    :field-names="{ label: labelField, value: valueField }"
    :filter-option="handleFilterOption"
    allowClear
  >
    <template #suffixIcon v-if="loading">
      <LoadingOutlined spin />
    </template>
    <template #notFoundContent v-if="loading">
      <span>
        <LoadingOutlined spin class="mr-1" />
        请等待数据加载完成...
      </span>
    </template>
  </a-select>
</template>
<script lang="ts" setup>
  import { ref, inject, watch, onMounted, watchEffect, computed } from 'vue';
  import { isFunction } from '/@/utils/is';
  import { LoadingOutlined } from '@ant-design/icons-vue';
  import { getDatasourceData } from '/@/api/system/datasource';
  import { getDicDetailList } from '/@/api/system/dic';
  import { camelCaseString, apiConfigFunc, isValidJSON } from '/@/utils/event/design';

  const props = defineProps({
    placeholder: { type: String },
    value: { type: [String, Number] },
    labelField: { type: String },
    valueField: { type: String },
    showSearch: { type: Boolean },
    disabled: { type: Boolean },
    readonly: { type: Boolean },
    params: {
      type: [Array, Object, String, Number],
    },
    immediate: {
      type: Boolean,
      default: true,
    },
    dataSourceOptions: { type: Array },
    dicOptions: { type: Array },
    //数据来源 默认为空  如果不为空 则参数 api
    datasourceType: String,
    api: {
      type: Function as PropType<(arg?: Recordable) => Promise<any[]>>,
      default: null,
    },
    apiConfig: Object,
    mainKey: String,
    index: Number,
    //填表按钮绑定使用
    prestrainField: String,
    style: Object,
    width: String,
  });
  const selectValue = ref<string | number | undefined>(undefined);
  const loading = ref(false);
  const options = ref<any[]>([]);
  const formModel = inject<any>('formModel', null);
  const isCamelCase = inject<boolean>('isCamelCase', false);
  const emit = defineEmits(['update:value', 'change']);
  onMounted(async () => {
    if (props.value) {
      await getOptions();
      changeData(props.value);
    }
  });

  watch(
    () => props.value,
    (val) => {
      selectValue.value = val || undefined;
    },
    {
      immediate: true,
    },
  );

  const handleFilterOption = (input: string, option) => {
    const label = option.label || option.name;
    return label.toLowerCase().includes(input.toLowerCase());
  };

  const handleSelectChange = (value) => {
    emit('update:value', value || '');
    emit('change', value || '');
    selectValue.value = props.value === undefined ? value : props.value;
    changeData(value);
  };
  function changeData(value) {
    let assoConfig =
      props.datasourceType === 'dic' ? props.dicOptions : props.apiConfig?.outputParams;
    if (!formModel) return;
    assoConfig?.map((item: any) => {
      if (item.bindField) {
        const index = options.value.findIndex((opt) => {
          return opt[props.valueField!] === value;
        });
        let bindField = !isCamelCase ? item.bindField : camelCaseString(item.bindField);
        let bindTable = '';
        if (item.bindTable) {
          bindTable = !isCamelCase
            ? item.bindTable + 'List'!
            : camelCaseString(item.bindTable + '_List')!;
        }
        let val = index === -1 ? '' : options.value[index][item.name];
        if (props.mainKey) {
          if (!item.bindTable) {
            formModel[bindField!] = val;
          } else {
            let subVal = val;
            if (formModel[props.mainKey][props.index!].isButtonSet) {
              const indexPrestrain = options.value.findIndex((opt) => {
                return opt[props.prestrainField!] === value;
              });
              subVal = indexPrestrain === -1 ? '' : options.value[indexPrestrain][item.name];
            }
            if (subVal) formModel[props.mainKey][props.index!][bindField!] = subVal;
          }
        } else {
          if (item.bindTable) {
            if (val) formModel[bindTable][0][bindField!] = val;
          } else {
            formModel[bindField!] = val;
          }
        }
      }
    });
  }
  const getOptions = async () => {
    let api;
    if (props.datasourceType) {
      if (props.datasourceType === 'dic') {
        api = getDicDetailList;
      } else if (props.datasourceType === 'datasource') {
        api = getDatasourceData;
      } else if (props.datasourceType === 'api' && props.apiConfig?.path) {
        options.value = await apiConfigFunc(props.apiConfig, isCamelCase, formModel, props.index);
        return;
      }
    } else {
      api = props.api;
    }
    options.value = [];
    if (!api || !isFunction(api)) return;
    try {
      if (!props.params) return;
      loading.value = true;
      const res = await api(props.params);

      if (Array.isArray(res)) {
        options.value = res;
        return;
      }
    } catch (error) {
      console.warn(error);
    } finally {
      loading.value = false;
    }
  };
  watchEffect(() => {
    if (props.datasourceType === 'api' && props.apiConfig?.apiParams) {
      props.apiConfig.apiParams.forEach((params) => {
        params.tableInfo?.forEach((o) => {
          if (o.bindType == 'data') {
            let val = isValidJSON(o.value);
            let field = '';
            if (val && val.bindTable) {
              let table = !isCamelCase
                ? val.bindTable + 'List'
                : camelCaseString(val.bindTable + '_List');
              field = !isCamelCase ? val.bindField : camelCaseString(val.bindField);
              formModel &&
                formModel[table!][props.index || 0] &&
                formModel[table!][props.index || 0][field];
            } else if (val && val.bindField) {
              field = !isCamelCase ? val.bindField : camelCaseString(val.bindField);
              formModel && formModel[field];
            }
          }
        });
      });
      getOptions();
    }
  });
  watch(
    () => [props.params, props.apiConfig],
    () => {
      getOptions();
    },
    {
      immediate: true,
      deep: true,
    },
  );
  watch(
    () => props.datasourceType,
    (curVal, oldVal) => {
      getOptions();
      if (!props.value || (curVal !== oldVal && !!oldVal)) selectValue.value = undefined;
    },
  );

  const color = computed(() => {
    return props.style?.color;
  });
  const backgroundcolor = computed(() => {
    return props.style
      ? props.style['background-color'] || (props.disabled ? '#f5f5f5' : '#fff')
      : '#fff';
  });
  const border = computed(() => {
    return props.style?.border || '1px solid #d9d9d9';
  });
  const fontsize = computed(() => {
    return props.style ? props.style['font-size'] : '14px';
  });
  const fontstyle = computed(() => {
    return props.style ? props.style['font-style'] : 'normal';
  });
  const customwidth = computed(() => {
    return props.style?.width || props.width;
  });
  const height = computed(() => {
    return props.style?.height || '32px';
  });
  const textalign = computed(() => {
    return props.style ? props.style['text-align'] : 'left';
  });
</script>
<style scoped lang="less">
  .customStyle {
    width: v-bind(customwidth);

    &.ant-select-disabled {
      :deep(.ant-select-selector) {
        background-color: v-bind(backgroundcolor);
      }
    }

    :deep(.ant-select-selector) {
      border: v-bind(border);
      background-color: v-bind(backgroundcolor);
      height: v-bind(height);
      font-size: v-bind(fontsize);
      font-style: v-bind(fontstyle);
    }

    :deep(.ant-select-selection-item) {
      color: v-bind(color);
      line-height: v-bind(height);
      text-align: v-bind(textalign);
    }

    :deep(.ant-select-selection-placeholder) {
      line-height: v-bind(height);
      text-align: v-bind(textalign);
    }
  }
</style>
