<script lang="ts" setup>
  import { Button, Transfer, Tag } from 'ant-design-vue';
  import { cloneDeep, get } from 'lodash-es';
  import { computed, CSSProperties, ExtractPropTypes, onMounted, ref, unref, watch } from 'vue';
  import { BasicModal, useModal } from '/@/components/Modal';
  import { isFunction } from '/@/utils/is';

  type TransferType = InstanceType<typeof Transfer>;

  interface Options {
    title?: string;
    key?: string;
    disabled?: boolean;
    description?: string;
  }

  const emit = defineEmits(['change', 'update:value']);

  const props = withDefaults(
    defineProps<{
      options?: Options[];
      maxTagLength?: number;
      value?: string[];
      api?: Fn<Recordable, Promise<Options[]>>;
      labelField?: string;
      valueField?: string;
      resultField?: string;
      params?: Recordable;
      buttonName?: string;
      modalProps?: ExtractPropTypes<InstanceType<typeof BasicModal>['$props']>;
      transferProps?: ExtractPropTypes<TransferType['$props']>;
      buttonProps?: ExtractPropTypes<InstanceType<typeof Button>['$props']>;
    }>(),
    {
      labelField: 'label',
      valueField: 'value',
      buttonName: '选择产品',
      maxTagLength: 2,
    }
  );

  const [register, { openModal }] = useModal();

  const options = ref<Options[]>([]);

  const loading = ref(false);

  const targetOptions = computed(() => {
    const { valueField } = props;
    return unref(getOptions).filter((item) => unref(targetKeys).includes(item[valueField]));
  });

  const getShowTagOptions = computed(() => {
    const { maxTagLength } = props;
    return unref(targetOptions).slice(0, maxTagLength);
  });

  const getSurplusOptionsLength = computed(() => {
    const { maxTagLength } = props;
    const surplusValue = unref(targetKeys).length - maxTagLength;
    return surplusValue < 0 ? 0 : surplusValue;
  });

  const count = computed(() => {
    return unref(targetKeys).length;
  });

  const targetKeys = ref<string[]>(props.value || []);

  const getOptions = computed<Recordable[]>(() => {
    const { labelField, valueField } = props;
    return unref(options).map((item) => ({
      ...item,
      title: item[labelField],
      key: item[valueField],
    }));
  });

  const getBindProps = computed(() => {
    const { transferProps = {} } = props;
    return {
      render: (item: Options) => item.title,
      listStyle: { height: '300px' } as CSSProperties,
      ...transferProps,
      targetKeys: unref(targetKeys),
      dataSource: unref(getOptions),
      onChange: handleChange,
    } as ExtractPropTypes<TransferType['$props']>;
  });

  const getBindModalProps = computed(() => {
    const { modalProps } = props;
    return {
      ...modalProps,
      title: '选择产品',
      showOkBtn: false,
    };
  });

  const getBindButtonProps = computed(() => {
    const { buttonProps = {} } = props;
    return {
      ...buttonProps,
      type: 'link',
      onClick: handleOpenModal,
    } as ExtractPropTypes<InstanceType<typeof Button>['$props']>;
  });

  const handleChange = (_targetKeys: string[], direction: 'left' | 'right', moveKeys: string[]) => {
    targetKeys.value = _targetKeys;
    emit('update:value', _targetKeys);
    const _targetOptions = cloneDeep(unref(targetOptions));
    emit('change', _targetKeys, _targetOptions, direction, moveKeys);
  };

  const handleGetOptions = async () => {
    try {
      loading.value = true;
      const { api, params, resultField, options: propsOptions } = props;
      if (api && isFunction(api)) {
        const res = await api(params!);
        if (Array.isArray(res)) {
          options.value = res;
          return;
        }
        if (resultField) {
          options.value = get(res, resultField) || [];
        }
      } else {
        if (propsOptions && Array.isArray(propsOptions)) {
          options.value = propsOptions;
        }
      }
    } catch (error) {
      throw error;
    } finally {
      loading.value = false;
    }
  };

  watch(
    () => props.value,
    () => {
      targetKeys.value = props.value || [];
    }
  );

  const handleOpenModal = () => {
    openModal(true);
  };

  onMounted(() => {
    handleGetOptions();
  });
</script>

<template>
  <div>
    <BasicModal v-bind="getBindModalProps" @register="register"   :maskClosable="false">
      <section class="flex justify-center items-center">
        <Transfer v-bind="getBindProps" />
      </section>
    </BasicModal>
    <Button v-bind="getBindButtonProps" class="!flex !justify-center !items-center min-h-8">
      <span v-if="!count">{{ $props.buttonName }}</span>
      <div v-if="!!count">
        <Tag
          class="!px-2 !py-1 !bg-gray-50 !border-gray-100"
          v-for="item in getShowTagOptions"
          :key="item.key"
        >
          <span>
            {{ item.title }}
          </span>
        </Tag>
        <Tag class="!px-2 !py-1 !bg-gray-50 !border-gray-100" v-if="getSurplusOptionsLength">
          <span> +{{ getSurplusOptionsLength }}... </span>
        </Tag>
      </div>
    </Button>
  </div>
</template>
