<template>
  <Modal
    title="选择处理方式"
    visible
    width="900px"
    okText="确定"
    cancelText="取消"
    :confirmLoading="loading"
    @ok="submitData"
    @cancel="cancel"
  >
    <div class="tip">
      <a-icon type="ExclamationCircleOutlined" />
      平台
      <span style="font-weight: bold; padding: 0 4px">物模型</span>
      中已有数据，请选择处理方式。
      <Tooltip title="默认采用覆盖的方式处理功能、事件、标签下的数据">
        <a-icon type="QuestionCircleOutlined" />
      </Tooltip>
    </div>
    <Form :layout="'vertical'" ref="formRef" :model="handleData">
      <FormItem label="处理方式" :rules="[{ required: true, message: '请选择处理方式' }]">
        <CardSelect v-model:value="handleData.type" :column="4" :options="options">
          <template #image="{ image }">
            <img :src="image" />
          </template>
        </CardSelect>
      </FormItem>
    </Form>
  </Modal>
</template>

<script lang="ts" setup name="MetadataModal">
  import { ref, reactive } from 'vue';
  import { useProductStore } from '@jdlinker/func';
  import { getImage } from '@jdlinker/utils';
  import { storeToRefs } from 'pinia';
  import { modify, updateDevice } from '../../../../../api/device/product';
  import { Tooltip, Form, FormItem } from 'ant-design-vue';
  // @ts-ignore
  import { message, Modal, CardSelect } from 'linker-ui-components';
  import { savePluginData } from '../../../../../api/link/plugin';

  type Emit = {
    (e: 'submit'): void;
    (e: 'cancel'): void;
  };

  const emit = defineEmits<Emit>();

  const props = defineProps({
    metadata: {
      type: Object,
      default: () => ({})
    },
    access: {
      type: Object,
      default: () => ({})
    },
    data: {
      type: Object,
      default: () => ({})
    }
  });

  const productStore = useProductStore();
  const { current: productDetail } = storeToRefs(productStore);
  const formRef = ref();
  const handleData = reactive({
    type: undefined
  });
  const loading = ref(false);
  const options = [
    {
      value: 'intersection',
      label: '取交集',
      subLabel: '仅保留标识一致的属性',
      iconUrl: getImage('/device/intersection.png')
    },
    {
      value: 'union',
      label: '取并集',
      subLabel: '保留平台、插件中的所有属性',
      iconUrl: getImage('/device/union.png')
    },
    {
      value: 'ignore',
      label: '忽略',
      subLabel: '仅保留平台中的属性',
      iconUrl: getImage('/device/ignore.png')
    },
    {
      value: 'cover',
      label: '覆盖',
      subLabel: '仅保留插件中的属性',
      iconUrl: getImage('/device/cover.png')
    }
  ];

  const flatObj = (obj: any, result: any) => {
    Object.keys(obj).forEach((key: string) => {
      if (typeof obj[key] === 'string') {
        result[key] = obj[key];
      } else {
        flatObj(obj[key], result);
      }
    });
  };

  const updateAccessData = async (id: string, values: any, metadata: string) => {
    const result: any = {};
    flatObj(values, result);
    const { storePolicy, ...extra } = result;
    // 更新选择设备(设备接入)
    const accessObj = {
      ...productDetail.value,
      metadata: JSON.stringify(metadata),
      transportProtocol: props.access?.transport,
      protocolName: props.access?.protocolDetail?.name,
      accessId: props.access?.id,
      accessName: props.access?.name,
      accessProvider: props.access?.provider,
      messageProtocol: props.access?.protocol
    };
    loading.value = true;
    const updateDeviceResp = await updateDevice(accessObj);

    if (!updateDeviceResp.success) {
      loading.value = false;
      return;
    }

    if (props.access?.provider === 'plugin_gateway' && props.data.productTypeId) {
      await savePluginData('product', props.access.id, props.data.id, props.data.productTypeId).catch(() => ({}));
    }

    // 更新产品配置信息
    const resp = await modify(id || '', {
      id: id,
      configuration: { ...extra },
      storePolicy: storePolicy
    });
    loading.value = false;
    if (resp.code === 200) {
      message.success('操作成功！');
      productStore.current!.storePolicy = storePolicy;
      if ((window as any).onTabSaveSuccess) {
        if (resp.result) {
          (window as any).onTabSaveSuccess(resp);
          setTimeout(() => window.close(), 300);
        }
      } else {
        await productStore.getDetail(productDetail.value.id);
        emit('submit');
      }
    }
  };

  const submitData = () => {
    formRef.value
      .validate()
      .then((res) => {
        if (res) {
          let metadata = JSON.parse(productDetail.value?.metadata || '{}'); // 产品物模型
          switch (handleData.type![0]) {
            case 'intersection': // 交集
              metadata.properties = IntersectionFn(metadata.properties, props.metadata.properties);
              metadata.events = IntersectionFn(metadata.events, props.metadata.events);
              metadata.functions = IntersectionFn(metadata.functions, props.metadata.functions);
              metadata.tags = IntersectionFn(metadata.tags, props.metadata.tags);
              break;
            case 'union': // 并集
              metadata.properties = UnionFn(metadata.properties, props.metadata.properties);
              metadata.functions = UnionFn(metadata.functions, props.metadata.functions);
              metadata.events = UnionFn(metadata.events, props.metadata.events);
              metadata.tags = UnionFn(metadata.tags, props.metadata.tags);
              break;
            case 'cover': // 覆盖
              metadata = props.metadata;
              break;
            default:
              break;
          }
          updateAccessData(props.data.id, props.data.values, metadata);
        }
      })
      .catch(() => {});
  };

  const cancel = () => {
    emit('cancel');
  };

  /**
   * 交集处理函数， 只保留来自插件中的属性
   * @param DataA 产品物模型
   * @param DataB 插件物模型
   * @constructor
   */
  const IntersectionFn = (DataA: any[] = [], DataB: any[] = []): any[] => {
    const newData: any[] = [];
    if (!DataA.length) return [];
    DataB.forEach((item) => {
      console.log(item, item.id);
      if (DataA.some((aItem) => aItem.id === item.id)) {
        newData.push(item);
      }
    });
    return newData;
  };

  /**
   * 并集函数处理，保留平台、插件中的所有属性，ID重复时，只保留来自插件中的1条属性。
   * @param DataA 产品物模型
   * @param DataB 插件物模型
   * @constructor
   */
  const UnionFn = (DataA: any[] = [], DataB: any[] = []): any[] => {
    const dataMap = new Map();

    DataB.forEach((item) => {
      dataMap.set(item.id, item);
    });

    DataA.forEach((item) => {
      if (!dataMap.has(item.id)) {
        dataMap.set(item.id, item);
      }
    });
    console.log(DataA, DataB, [...dataMap.values()]);
    return [...dataMap.values()];
  };
</script>

<style scoped lang="less">
  .tip {
    background: #f6f6f6;
    color: #999;
    padding: 10px 26px;
    margin-bottom: 24px;
  }
  :deep(.j-card-item) {
    padding: 16px !important;
  }
</style>
