<template>
  <div>
    <div class="top">
      <div class="top-left">
        <div>
          <AIcon type="ExclamationCircleOutlined" />
          <template v-if="topTitle === 'rest'">
            当前数据解析内容已脱离产品影响，
            <PermissionButton type="link" hasPermission="device/Instance:update" @click="rest()"> 重置 </PermissionButton>
            后将继承产品数据解析内容
          </template>
          <template v-else>
            当前数据解析内容继承自产品,
            <PermissionButton type="link" hasPermission="device/Instance:update" @click="readOnly = false" :style="color">
              修改
            </PermissionButton>
            后将脱离产品影响。
          </template>
        </div>
      </div>
      <div>
        脚本语言:
        <Select :defaultValue="'JavaScript'" style="width: 200px; margin-left: 5px">
          <SelectOption value="JavaScript">JavaScript(ECMAScript 5)</SelectOption>
        </Select>
        <AIcon type="ExpandOutlined" style="margin-left: 20px" @click="toggle" />
      </div>
    </div>
    <div class="edit" ref="el">
      <div
        v-show="readOnly"
        class="edit-only"
        @click="
          () => {
            message.warning({
              key: 1,
              content: () => '请点击上方修改字样,用以编辑脚本',
              style: {
                marginTop: '260px'
              }
            });
          }
        "
      ></div>
      <MonacoEditor
        language="javascript"
        style="height: 100%"
        theme="vs"
        v-model:modelValue="editorValue"
        :registrationTypescript="typescriptTip"
        :init="editorInit"
      />
    </div>
    <div class="bottom">
      <div style="width: 49.5%">
        <div class="bottom-title">
          <div class="bottom-title-text">模拟输入</div>
          <div class="bottom-title-topic">
            <template v-if="instanceStore.current.transport === 'MQTT'">
              <div style="margin-right: 5px">Topic:</div>
              <AutoComplete
                placeholder="请输入Topic"
                style="width: 300px"
                :options="topicList"
                :allowClear="true"
                :filterOption="filterOption"
                v-model:value="topic"
              />
            </template>
            <template v-else>
              <div style="margin-right: 5px">URL:</div>
              <Input placeholder="请输入URL" v-model:value="url" style="width: 300px" />
            </template>
          </div>
        </div>
        <Textarea
          :rows="5"
          placeholder="// 二进制数据以0x开头的十六进制输入，字符串数据输入原始字符串"
          style="margin-top: 10px"
          v-model:value="simulation"
        />
      </div>
      <div style="width: 49.5%">
        <div class="bottom-title">
          <div class="bottom-title-text">运行结果</div>
        </div>
        <Textarea :autoSize="{ minRows: 5 }" :style="resStyle" v-model:value="result" />
      </div>
    </div>
  </div>
  <div style="margin-top: 10px; margin-left: 10px">
    <PermissionButton
      type="primary"
      hasPermission="device/Instance:update"
      :loading="loading"
      :disabled="isDisabled"
      @click="debug()"
      :tooltip="{
        title: '需输入脚本和模拟数据后再点击'
      }"
    >
      调试
    </PermissionButton>
    <PermissionButton
      hasPermission="device/Instance:update"
      :loading="loading"
      :disabled="!isTest"
      @click="save()"
      :style="{ marginLeft: '10px' }"
      :tooltip="{
        title: isTest ? '' : '请先调试'
      }"
    >
      保存
    </PermissionButton>
  </div>
</template>

<script setup lang="ts" name="Parsing">
  import { ref, reactive, computed, watch } from 'vue';
  import { onlyMessage } from '@jdlinker/utils';
  import { useFullscreen } from '@vueuse/core';
  import { useInstanceStore } from '@jdlinker/func';
  import { deviceCode, getProtocal, testCode, saveDeviceCode, delDeviceCode } from '../../../../../api/device/instance';
  import { isBoolean } from 'lodash-es';
  import { PermissionButton } from '@jdlinker/ui';
  // @ts-ignore
  import { AIcon, Select, SelectOption, Textarea, AutoComplete, Input, MonacoEditor } from 'linker-ui-components';

  const defaultValue = `//注册设备下行数据监听器,当平台下发指令给设备时,回调将被调用,用于构造下发给设备的报文
      codec.onDownstream(function(ctx){

      });

      //注册设备上行数据监听器,当设备上行数据时,回调将被调用,用于解析设备上报的数据.
      codec.onUpstream(function(ctx){

      });
    `;

  const el = ref<HTMLElement | null>(null);
  const { toggle } = useFullscreen(el);
  const instanceStore = useInstanceStore();

  const topTitle = ref<string>('');
  const readOnly = ref<boolean>(true);
  const url = ref<string>('');
  const topic = ref<string>('');
  const topicList = ref([]);
  const simulation = ref<string>('');
  const resultValue = ref<any>({});
  const loading = ref<boolean>(false);
  const isTest = ref<boolean>(false);
  const editorValue = ref<string>('');

  const typescriptTip = reactive({
    typescript: ''
  });

  const color = computed(() => ({
    color: readOnly.value ? '#415ed1' : '#a6a6a6'
  }));
  const resStyle = computed(() =>
    isBoolean(resultValue.value.success)
      ? {
          'margin-top': '10px',
          'border-color': resultValue.value.success ? 'green' : 'red'
        }
      : {
          'margin-top': '10px'
        }
  );
  const filterOption = (inputValue: any, option: any) => option!.value.indexOf(inputValue) !== -1;

  const isDisabled = computed(() => simulation.value === '');

  const result = computed(() =>
    resultValue.value.success ? JSON.stringify(resultValue.value.outputs?.[0]) : resultValue.value.reason
  );

  const editorInit = (editor: any, monaco: any) => {
    monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
      noSemanticValidation: true,
      noSyntaxValidation: false
    });

    // compiler options
    monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
      allowJs: true,
      checkJs: true,
      allowNonTsExtensions: true,
      target: monaco.languages.typescript.ScriptTarget.ESNext,
      strictNullChecks: false,
      strictPropertyInitialization: true,
      strictFunctionTypes: true,
      strictBindCallApply: true,
      useDefineForClassFields: true, //permit class static fields with private name to have initializer
      moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
      module: monaco.languages.typescript.ModuleKind.CommonJS,
      typeRoots: ['types'],
      lib: ['esnext']
    });
  };

  //重置
  const rest = async () => {
    const res = await delDeviceCode(instanceStore.current.productId, instanceStore.current.id);
    if (res.status === 200) {
      getDeviceCode();
      onlyMessage('操作成功');
    }
  };
  //获取topic
  const getTopic = async () => {
    const res: any = await getProtocal(instanceStore.current.protocol, instanceStore.current.transport);
    if (res.code === 200) {
      const item = res.result.routes?.map((items: any) => ({
        value: items.topic
      }));
      // setTopicList(item);
      topicList.value = item;
    }
  };

  // const queryCode = () => {
  //   queryCodeTips(instanceStore.current.productId, instanceStore.current.id).then((res) => {
  //     if (res.success) {
  //       typescriptTip.typescript = res.result;
  //     }
  //   });
  // };

  //获取设备解析规则
  const getDeviceCode = async () => {
    const res: any = await deviceCode(instanceStore.current.productId, instanceStore.current.id);

    if (res.status === 200) {
      const item = res.result?.configuration?.script ? res.result?.configuration?.script : defaultValue;
      if (res.result?.deviceId) {
        readOnly.value = false;
        topTitle.value = 'rest';
        editorValue.value = item;
      } else {
        readOnly.value = true;
        topTitle.value = 'edit';
        editorValue.value = item;
      }
    }
  };
  //调试
  const test = async (dataTest: any) => {
    loading.value = true;
    const res = await testCode(dataTest);
    if (res.status === 200) {
      loading.value = false;
      resultValue.value = res?.result;
    } else {
      loading.value = false;
    }
  };

  //保存设备解析规则
  const save = async () => {
    const item = {
      provider: 'jsr223',
      configuration: {
        script: editorValue.value,
        lang: 'javascript'
      }
    };
    const res = await saveDeviceCode(instanceStore.current.productId, instanceStore.current.id, item);
    if (res.status === 200) {
      onlyMessage('保存成功');
      getDeviceCode();
    }
  };

  const debug = () => {
    if (instanceStore.current.transport === 'MQTT') {
      if (topic.value !== '') {
        test({
          headers: {
            topic: topic.value
          },
          configuration: {
            script: editorValue.value,
            lang: 'javascript'
          },
          provider: 'jsr223',
          payload: simulation.value
        });
        isTest.value = true;
      } else {
        onlyMessage('请输入topic', 'error');
      }
    } else {
      if (url.value !== '') {
        test({
          headers: {
            url: url.value
          },
          provider: 'jsr223',
          configuration: {
            script: editorValue.value,
            lang: 'javascript'
          },
          payload: simulation.value
        });
        isTest.value = true;
      } else {
        onlyMessage('请输入url', 'error');
      }
    }
  };

  // onMounted(() => {
  //     getDeviceCode();
  //     getTopic();
  // });

  watch(
    () => instanceStore.current?.id,
    () => {
      if (instanceStore.current?.id) {
        getDeviceCode();
        getTopic();
        // queryCode();
      }
    },
    { immediate: true }
  );
</script>

<style scoped lang="less">
  .top {
    display: flex;
    justify-content: space-between;
    margin-bottom: 10px;

    .top-left {
      display: flex;
      align-items: center;
    }
  }

  .edit {
    height: 550px;
    border: 1px solid #dcdcdc;

    .edit-only {
      height: 550px;
      width: 97%;
      position: absolute;
      z-index: 1;
      background-color: #eeeeee70;
      cursor: not-allowed;
    }
  }

  .bottom {
    display: flex;
    justify-content: space-between;
    padding: 10px;
    background-color: #f7f7f7;

    .bottom-title {
      display: flex;
      justify-content: space-between;

      .bottom-title-text {
        font-weight: 600;
        font-size: 14px;
        margin-top: 10px;
      }

      .bottom-title-topic {
        display: flex;
        align-items: center;
      }
    }
  }
</style>
