<template>
  <Modal
    :centered="true"
    :mask-closable="false"
    title="导入物模型"
    destroy-on-close
    v-model:visible="_visible"
    @cancel="close"
    @ok="handleImport"
    :confirm-loading="loading"
  >
    <div class="import-content">
      <p class="import-tip">
        <AIcon type="ExclamationCircleOutlined" style="margin-right: 5px" />
        导入的物模型会覆盖原来的属性、功能、事件、标签，请谨慎操作。
      </p>
    </div>
    <Form layout="vertical" v-model:value="formModel">
      <FormItem v-if="type === 'product'" label="导入方式" v-bind="validateInfos.type">
        <Select v-model:value="formModel.type">
          <SelectOption value="copy">拷贝产品</SelectOption>
          <SelectOption value="import">导入物模型</SelectOption>
        </Select>
      </FormItem>
      <FormItem label="选择产品" v-bind="validateInfos.copy" v-if="formModel.type === 'copy'">
        <Select :options="productList" v-model:value="formModel.copy" option-filter-prop="label" showSearch />
      </FormItem>
      <FormItem label="物模型类型" v-bind="validateInfos.metadata" v-if="type === 'device' || formModel.type === 'import'">
        <Select v-model:value="formModel.metadata">
          <SelectOption value="jdlinker">Jdlinker物模型</SelectOption>
          <SelectOption value="alink">阿里云物模型TSL</SelectOption>
        </Select>
      </FormItem>
      <FormItem
        label="导入类型"
        v-bind="validateInfos.metadataType"
        v-if="type === 'device' || formModel.type === 'import'"
      >
        <Select v-model:value="formModel.metadataType">
          <SelectOption value="file">文件上传</SelectOption>
          <SelectOption value="script">脚本</SelectOption>
        </Select>
      </FormItem>
      <FormItem label="文件上传" v-bind="validateInfos.upload" v-if="formModel.metadataType === 'file'">
        <Input v-model:value="formModel.upload">
          <template #addonAfter>
            <Upload
              v-model:file-list="fileList"
              :before-upload="beforeUpload"
              accept=".json"
              :show-upload-list="false"
              :action="FILE_UPLOAD"
              @change="fileChange"
              :headers="{
                [TOKEN_KEY]: getToken()
              }"
            >
              <AIcon type="UploadOutlined" class="upload-button" />
            </Upload>
          </template>
        </Input>
      </FormItem>
      <FormItem
        v-bind="validateInfos.import"
        v-if="(type === 'device' || formModel.type === 'import') && formModel.metadataType === 'script'"
      >
        <template #label>
          <Space>
            物模型
            <Tooltip title="在线编辑器中编写物模型脚本">
              <AIcon type="QuestionCircleOutlined" style="color: rgb(136, 136, 136)" />
            </Tooltip>
          </Space>
        </template>
        <MonacoEditor v-model:value="formModel.import" theme="vs" style="height: 250px" lang="json" />
      </FormItem>
    </Form>
  </Modal>
</template>
<script setup lang="ts" name="Import">
  import { ref, computed, reactive } from 'vue';
  import { useForm } from 'ant-design-vue/es/form';
  import { saveMetadata } from '../../../../../api/device/instance';
  import { queryNoPagingPost, convertMetadata, modify } from '../../../../../api/device/product';
  import type { DefaultOptionType } from 'ant-design-vue/es/select';
  import type { UploadProps, UploadFile, UploadChangeParam } from 'ant-design-vue/es';
  import type { DeviceMetadata } from '../../../Product/typings';
  // @ts-ignore
  import { message, AIcon, Tooltip, Space, Modal, Form, FormItem, Select, MonacoEditor, Input, SelectOption, Upload } from 'linker-ui-components';
  import { useInstanceStore, getToken, useProductStore, useMetadataStore } from '@jdlinker/func';
  import { FILE_UPLOAD } from '../../../../../api/comm';
  import { TOKEN_KEY } from '@jdlinker/utils';

  const instanceStore = useInstanceStore();
  const productStore = useProductStore();

  interface Props {
    visible: boolean;
    type: 'device' | 'product';
  }
  interface Emits {
    (e: 'update:visible', data: boolean): void;
  }
  const props = defineProps<Props>();
  const emits = defineEmits<Emits>();
  const loading = ref(false);

  const _visible = computed({
    get: () => {
      return props.visible;
    },
    set: (val: any) => {
      emits('update:visible', val);
    }
  });

  const close = () => {
    emits('update:visible', false);
  };

  /** form表单 */
  const formModel = reactive<any>({
    type: 'import',
    metadata: 'jdlinker',
    metadataType: 'file'
  });
  const rules = reactive({
    type: [
      {
        required: true,
        message: '请选择导入方式'
      }
    ],
    copy: [
      {
        required: true,
        message: '请选择产品'
      }
    ],
    metadata: [
      {
        required: true,
        message: '请选择物模型类型'
      }
    ],
    metadataType: [
      {
        required: true,
        message: '请选择导入类型'
      }
    ],
    upload: [
      {
        required: true,
        message: '请上传文件'
      }
    ],
    import: [
      {
        required: true,
        message: '请输入物模型'
      }
    ]
  });
  const { validate, validateInfos } = useForm(formModel, rules);
  const fileList = ref<UploadFile[]>([]);

  const productList = ref<DefaultOptionType[]>([]);

  const loadData = async () => {
    const { id } = props.type === 'device' ? instanceStore.current?.id : productStore.current?.id;
    const product = (await queryNoPagingPost({
      paging: false,
      sorts: [{ name: 'createTime', order: 'desc' }],
      terms: [{ column: 'id$not', value: id }]
    })) as any;
    productList.value = product.result
      .filter((i: any) => i?.metadata)
      .map((item: any) => ({
        label: item.name,
        value: item.metadata,
        key: item.id
      })) as DefaultOptionType[];
  };
  loadData();

  const beforeUpload: UploadProps['beforeUpload'] = (file) => {
    const reader = new FileReader();
    reader.readAsText(file);
    reader.onload = (json) => {
      formModel.import = json.target?.result;
    };
  };
  const fileChange = (info: UploadChangeParam) => {
    if (info.file.status === 'done') {
      const { response } = info.file;
      if (response.code === 200) {
        formModel.upload = response.result.downloadUrl;
      }
    }
  };

  const operateLimits = (mdata: DeviceMetadata) => {
    const obj: DeviceMetadata = { ...mdata };
    const old = JSON.parse(instanceStore.detail?.metadata || '{}');
    const fid = instanceStore.detail?.features?.map((item) => item.id);
    if (fid?.includes('eventNotModifiable')) {
      obj.events = old?.events || [];
    }
    if (fid?.includes('propertyNotModifiable')) {
      obj.properties = old?.properties || [];
    }
    (obj?.events || []).map((item, index) => {
      return { ...item, sortsIndex: index };
    });
    (obj?.properties || []).map((item, index) => {
      return { ...item, sortsIndex: index };
    });
    (obj?.functions || []).map((item, index) => {
      return { ...item, sortsIndex: index };
    });
    (obj?.tags || []).map((item, index) => {
      return { ...item, sortsIndex: index };
    });
    return obj;
  };
  const metadataStore = useMetadataStore();
  const handleImport = async () => {
    validate().then(async (data) => {
      loading.value = true;
      const id = props.type === 'device' ? instanceStore.current?.id : productStore.current?.id;
      if (data.metadata === 'alink') {
        const res = await convertMetadata('from', 'alink', JSON.parse(data.import)).catch((err) => err);
        if (res.code === 200) {
          const metadata = operateLimits(res.result);
          let result;
          if (props?.type === 'device') {
            result = await saveMetadata(id as string, metadata).catch((err) => err);
          } else {
            result = await modify(id as string, { id, metadata: JSON.stringify(metadata) }).catch((err) => err);
          }
          if (result.success) {
            message.success('导入成功');
          }
          loading.value = false;
        } else {
          loading.value = false;
          // message.error('物模型数据不正确!')
          return;
        }
        if (props?.type === 'device') {
          await instanceStore.refresh(id as string);
        } else {
          await productStore.getDetail(id as string);
        }
        metadataStore.set('importMetadata', true);
        // Store.set(SystemConst.GET_METADATA, true)
        // Store.set(SystemConst.REFRESH_METADATA_TABLE, true)
        close();
      } else {
        try {
          const _object = JSON.parse(data[props?.type === 'device' ? 'import' : data?.type] || '{}');
          if (!(!!_object?.properties || !!_object?.events || !!_object?.functions || !!_object?.tags)) {
            message.error('物模型数据不正确');
            loading.value = false;
            return;
          }
          const id = props.type === 'device' ? instanceStore.current?.id : productStore.current?.id;
          const params = {
            id,
            metadata: JSON.stringify(operateLimits(_object as DeviceMetadata))
          };
          const paramsDevice = operateLimits(_object as DeviceMetadata);
          let resp = undefined;
          if (props?.type === 'device') {
            resp = await saveMetadata(id as string, paramsDevice);
          } else {
            resp = await modify(id as string, params);
          }
          loading.value = false;
          if (resp.success) {
            message.success('导入成功');
          }
          if (props?.type === 'device') {
            await instanceStore.refresh(id as string);
          } else {
            await productStore.getDetail(id as string);
          }
          metadataStore.set('importMetadata', true);
          // Store.set(SystemConst.GET_METADATA, true)
          // Store.set(SystemConst.REFRESH_METADATA_TABLE, true)
          close();
        } catch (e) {
          loading.value = false;
          message.error(e === 'error' ? '物模型数据不正确' : '上传json格式的物模型文件');
        }
      }
    });
  };

  // const showProduct = computed(() => formModel.type === 'copy')
</script>
<style scoped lang="less">
  .import-content {
    background: rgb(236, 237, 238);

    .import-tip {
      padding: 10px;
    }
  }

  .upload-button {
    width: 37px;
    height: 30px;
    line-height: 30px;
    margin: 0 -11px;
  }
</style>
