<template>
  <div>
    <template v-if="type === 'vue' || type === '远程vue组件'">
      <div v-if="remote">
        <component
          :is="remote"
          @change-event="changeEvent"
          v-model:value="compValue"
          :disabled="disabled"
          :allowClear="allowClear"
          :apiData="apiData"
        />
      </div>
    </template>
    <template v-else>
      <template v-if="type === 'html'">
        <iframe ref="iframeRef" :srcdoc="scriptValue" @load="onIframeLoad"></iframe>
      </template>
      <template v-else>
        <iframe ref="iframeUrlRef" :src="props.compUrl"></iframe>
      </template>
    </template>
  </div>
</template>
<script setup lang="ts">
  import * as Vue from 'vue';
  import { inject, onMounted, onUnmounted, ref, watch } from 'vue';
  import { loadModule, Options } from 'vue3-sfc-loader';
  import * as antd from 'ant-design-vue';
  import * as echarts from 'echarts';
  import * as icon from '@ant-design/icons-vue';
  import { getCustomComp } from '/@/api/system/customcomp';
  import { apiConfigFunc } from '/@/utils/event/design';
  const remote = ref();
  const formModel = inject<any>('formModel', null);
  const isCamelCase = inject<boolean>('isCamelCase', false);
  const emit = defineEmits(['update:value', 'update:content', 'change']);
  const apiData = ref(null);
  const compValue = ref();
  const iframeRef = ref();
  const iframeUrlRef = ref();
  const scriptValue = ref();
  const props = defineProps({
    value: { type: [String, Number] },
    /**
     * 类型
     */
    type: { type: String, required: true },
    /**
     * 内容
     */
    content: { type: String, required: false },
    id: { type: String, required: false },
    compUrl: { type: String, required: false },
    disabled: { type: Boolean },
    allowClear: { type: Boolean },
    apiConfig: {
      type: Object,
      default: () => {
        return {
          path: '',
          method: 'GET',
          apiId: '',
        };
      },
    },
    index: Number,
  });
  watch(
    () => props.value,
    async (val) => {
      compValue.value = val;
      onIframeTwoLoad();
    },
  );
  watch(
    () => compValue.value,
    async (val) => {
      emit('update:value', val);
    },
  );
  watch(
    () => props.content,
    async (val) => {
      if (props.type === 'vue') {
        scriptValue.value = val;
        await loadVue();
      } else if (props.type === 'html') {
        scriptValue.value = val;
        await loadVue();
      }
    },
  );
  watch(
    () => props.compUrl,
    async (val) => {
      if (props.type === '远程vue组件') await loadVue(val);
    },
  );
  watch(
    () => props.type,
    async () => {
      await changeCode();
    },
  );
  watch(
    () => [props.disabled, props.allowClear],
    () => {
      if (props.type === 'html') {
        onIframeLoad();
      } else {
        onIframeTwoLoad();
      }
    },
  );
  const onIframeLoad = () => {
    if (iframeRef.value) {
      const iframeWindow = iframeRef.value.contentWindow;
      iframeWindow.postMessage({
        message: compValue.value,
        disabled: props.disabled,
        allowClear: props.allowClear,
      });
    }
  };
  const onIframeTwoLoad = () => {
    if (iframeUrlRef.value) {
      const iframeWindow = iframeUrlRef.value.contentWindow;
      iframeWindow.postMessage(
        { message: compValue.value, disabled: props.disabled, allowClear: props.allowClear },
        '*',
      );
    }
  };
  onMounted(async () => {
    await changeCode();
    if (props.apiConfig && props.apiConfig.apiId) {
      await getApiData();
    }
  });

  onUnmounted(() => {
    window.removeEventListener('message', (_e) => {
      //TODO
    });
  });
  async function getApiData() {
    try {
      let res = await apiConfigFunc(props.apiConfig, isCamelCase, formModel, props.index);
      apiData.value = res;
    } catch {
      console.error('从接口配置中获取数据失败！');
    }
  }
  async function changeCode() {
    if (props.type === 'vue') {
      if (props.id && !props.content) {
        let res = await getCustomComp(props.id);
        scriptValue.value = res.bianXieQu9373;
        emit('update:content', scriptValue);
      } else if (props.content) {
        scriptValue.value = props.content;
        await loadVue();
      }
    } else if (props.type === '远程vue组件') {
      await loadVue(props.compUrl);
    } else if (props.type === 'html') {
      if (props.id && !props.content) {
        let res = await getCustomComp(props.id);
        scriptValue.value = res.bianXieQu9373;
        emit('update:content', scriptValue);
      } else if (props.content) {
        scriptValue.value = props.content;
      }

      window.addEventListener(
        'message',
        (e) => {
          if (e.source == iframeRef.value?.contentWindow) {
            emit('update:value', e.data.value);
            emit('change', e.data);
          }
        },
        false,
      );
    } else {
      window.addEventListener(
        'message',
        (e) => {
          if (e.source == iframeUrlRef.value?.contentWindow) {
            emit('update:value', e.data.value);
            emit('change', e.data);
          }
        },
        false,
      );
    }
  }
  async function loadVue(url?) {
    const options: Options = {
      moduleCache: {
        vue: Vue,
        'ant-design-vue': antd,
        echarts: echarts,
        '@ant-design/icons-vue': icon,
      },
      async getFile() {
        if (url) {
          try {
            const response = await fetch(url);
            if (!response.ok) {
              throw new Error(`HTTP error! status: ${response.status}`);
            }
            const result = await response.text();
            return result;
          } catch (error) {
            console.log(error);
          }
        } else {
          return scriptValue.value;
        }
      },
      addStyle(textContent) {
        const style = Object.assign(document.createElement('style'), { textContent });
        const ref = document.head.getElementsByTagName('style')[0] || null;
        document.head.insertBefore(style, ref);
      },
    };
    // 加载远程组件
    remote.value = await loadModule('loader.vue', options);
    // const comp = defineAsyncComponent(() => remote);
    //console.log(props.type, props.content, remote.value);
  }

  function changeEvent(_value: string) {
    emit('update:value', _value);
    emit('change', _value);
  }
</script>
