<template>
  <div class="m-editor-data-source-field-select">
    <template v-if="dataSourceId">
      <TMagicCascader
        :model-value="selectFieldsId"
        clearable
        filterable
        :size="size"
        :disabled="disabled"
        :options="fieldsOptions"
        :props="{
          checkStrictly,
        }"
        @change="fieldChangeHandler"
      ></TMagicCascader>
    </template>

    <template v-else-if="checkStrictly">
      <TMagicSelect
        :model-value="selectDataSourceId"
        clearable
        filterable
        :size="size"
        :disabled="disabled"
        @change="dsChangeHandler"
      >
        <component
          v-for="option in dataSourcesOptions"
          class="tmagic-design-option"
          :key="option.value"
          :is="optionComponent?.component || 'el-option'"
          v-bind="
            optionComponent?.props({
              label: option.text,
              value: option.value,
              disabled: option.disabled,
            }) || {
              label: option.text,
              value: option.value,
              disabled: option.disabled,
            }
          "
        >
        </component>
      </TMagicSelect>

      <TMagicCascader
        :model-value="selectFieldsId"
        clearable
        filterable
        :size="size"
        :disabled="disabled"
        :options="fieldsOptions"
        :props="{
          checkStrictly,
        }"
        @change="fieldChangeHandler"
      ></TMagicCascader>
    </template>

    <TMagicCascader
      v-else
      clearable
      filterable
      :model-value="modelValue"
      :disabled="disabled"
      :size="size"
      :options="cascaderOptions"
      :props="{
        checkStrictly,
      }"
      @change="onChangeHandler"
    ></TMagicCascader>

    <TMagicTooltip
      v-if="selectDataSourceId && hasDataSourceSidePanel && !isCompare"
      :content="notEditable ? '查看' : '编辑'"
    >
      <TMagicButton class="m-fields-select-action-button" :size="size" @click="editHandler(selectDataSourceId)"
        ><MIcon :icon="!notEditable ? Edit : View"></MIcon
      ></TMagicButton>
    </TMagicTooltip>
  </div>
</template>

<script lang="ts" setup>
import { computed, inject, ref, watch } from 'vue';
import { Edit, View } from '@element-plus/icons-vue';

import type { DataSourceFieldType } from '@tmagic/core';
import { getDesignConfig, TMagicButton, TMagicCascader, TMagicSelect, TMagicTooltip } from '@tmagic/design';
import { type FilterFunction, filterFunction, type FormState, type SelectOption } from '@tmagic/form';
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, removeDataSourceFieldPrefix } from '@tmagic/utils';

import MIcon from '@editor/components/Icon.vue';
import { useServices } from '@editor/hooks/use-services';
import { type EventBus, SideItemKey } from '@editor/type';
import { getCascaderOptionsFromFields } from '@editor/utils';

const props = defineProps<{
  /**
   * 是否要编译成数据源的data。
   * key: 不编译，就是要数据源id和field name;
   * value: 要编译（数据源data[`${filed}`]）
   * */
  value?: 'key' | 'value';
  disabled?: boolean;
  checkStrictly?: boolean;
  size?: 'large' | 'default' | 'small';
  dataSourceFieldType?: DataSourceFieldType[];
  /** 是否可以编辑数据源，disable表示的是是否可以选择数据源 */
  notEditable?: boolean | FilterFunction;
  /** 指定数据源ID，限定只能选择该数据源的字段 */
  dataSourceId?: string;
}>();

const emit = defineEmits<{
  change: [v: string[]];
}>();

const modelValue = defineModel<string[] | any>('modelValue', { default: [] });

const optionComponent = getDesignConfig('components')?.option;

const { dataSourceService, uiService } = useServices();
const mForm = inject<FormState | undefined>('mForm');
const eventBus = inject<EventBus>('eventBus');

const allDataSources = computed(() => dataSourceService.get('dataSources') || []);

const dataSources = computed(() => {
  if (!props.dataSourceId) return allDataSources.value;
  return allDataSources.value.filter((ds) => ds.id === props.dataSourceId);
});

const valueIsKey = computed(() => props.value === 'key');
const notEditable = computed(() => filterFunction(mForm, props.notEditable, props));

/** 对比模式下隐藏查看/编辑操作按钮，仅保留只读展示。 */
const isCompare = computed(() => Boolean(mForm?.isCompare));

const dataSourcesOptions = computed<SelectOption[]>(() =>
  dataSources.value.map((ds) => ({
    text: ds.title || ds.id,
    value: valueIsKey.value ? ds.id : `${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}${ds.id}`,
  })),
);

const selectDataSourceId = ref('');

const selectFieldsId = ref<string[]>([]);

watch(
  modelValue,
  (value) => {
    if (props.dataSourceId) {
      const dsIdValue = valueIsKey.value
        ? props.dataSourceId
        : `${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}${props.dataSourceId}`;
      selectDataSourceId.value = dsIdValue;
      selectFieldsId.value = Array.isArray(value) ? value : [];
    } else if (Array.isArray(value) && value.length) {
      const [dsId, ...fields] = value;
      selectDataSourceId.value = dsId;
      selectFieldsId.value = fields;
    } else {
      selectDataSourceId.value = '';
      selectFieldsId.value = [];
    }
  },
  {
    immediate: true,
  },
);

const fieldsOptions = computed(() => {
  const ds = allDataSources.value.find((ds) => ds.id === removeDataSourceFieldPrefix(selectDataSourceId.value));

  if (!ds) return [];

  return getCascaderOptionsFromFields(ds.fields, props.dataSourceFieldType);
});

const cascaderOptions = computed(() => {
  const options =
    dataSources.value?.map((ds) => ({
      label: ds.title || ds.id,
      value: valueIsKey.value ? ds.id : `${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}${ds.id}`,
      children: getCascaderOptionsFromFields(ds.fields, props.dataSourceFieldType),
    })) || [];
  return options.filter((option) => option.children.length);
});

const dsChangeHandler = (v: string) => {
  modelValue.value = [v];
  emit('change', modelValue.value);
};

const fieldChangeHandler = (v: string[] = []) => {
  if (props.dataSourceId) {
    modelValue.value = v;
    emit('change', v);
  } else {
    modelValue.value = [selectDataSourceId.value, ...v];
    emit('change', modelValue.value);
  }
};

const onChangeHandler = (v: string[] = []) => {
  modelValue.value = v;
  emit('change', v);
};

const dataSourceSidePanel = computed(() =>
  uiService.get('sideBarItems').find((item) => item.$key === SideItemKey.DATA_SOURCE),
);

const hasDataSourceSidePanel = computed(() => dataSourceSidePanel.value);

const editHandler = (id: string) => {
  const sideBarItem = dataSourceSidePanel.value;
  if (sideBarItem) {
    uiService.set('sideBarActiveTabName', sideBarItem.text || sideBarItem.$key || SideItemKey.DATA_SOURCE);
  }

  const dataSourceId = removeDataSourceFieldPrefix(id);
  const fieldPath = selectFieldsId.value;

  if (fieldPath.length) {
    eventBus?.emit('edit-data-source-field', dataSourceId, [...fieldPath]);
  } else {
    eventBus?.emit('edit-data-source', dataSourceId);
  }
};
</script>
