<template>
  <!-- 代码块编辑区 -->
  <FloatingBox v-model:visible="boxVisible" title="代码编辑" :position="boxPosition" :before-close="beforeClose">
    <template #body>
      <div ref="floatingBoxBody"></div>
    </template>
  </FloatingBox>

  <Teleport :to="floatingBoxBody" :disabled="slideType === 'box'" v-if="editVisible">
    <MFormBox
      class="m-editor-code-block-editor"
      ref="formBox"
      label-width="80px"
      :close-on-press-escape="false"
      :title="content.name"
      :width="size"
      :config="functionConfig"
      :values="content"
      :disabled="disabled"
      @change="changeHandler"
      @submit="submitForm"
      @error="errorHandler"
      @open="openHandler"
      @closed="closedHandler"
    >
      <template #left>
        <TMagicButton type="primary" link @click="difVisible = true">查看修改</TMagicButton>
      </template>
    </MFormBox>
  </Teleport>

  <TMagicDialog v-model="difVisible" title="查看修改" fullscreen>
    <div style="display: flex; margin-bottom: 10px">
      <div style="flex: 1"><TMagicTag size="small" type="info">修改前</TMagicTag></div>
      <div style="flex: 1"><TMagicTag size="small" type="success">修改后</TMagicTag></div>
    </div>

    <CodeEditor
      v-if="difVisible"
      ref="magicVsEditor"
      type="diff"
      language="json"
      :initValues="content.content"
      :modifiedValues="formBox?.form?.values.content"
      :style="`height: ${height - 200}px`"
    ></CodeEditor>

    <template #footer>
      <span class="dialog-footer">
        <TMagicButton size="small" @click="difVisible = false">取消</TMagicButton>
        <TMagicButton size="small" type="primary" @click="diffChange">确定</TMagicButton>
      </span>
    </template>
  </TMagicDialog>
</template>

<script lang="ts" setup>
import { computed, inject, nextTick, onBeforeUnmount, ref } from 'vue';

import { TMagicButton, TMagicDialog, tMagicMessage, tMagicMessageBox, TMagicTag } from '@tmagic/design';
import { ColumnConfig, FormConfig, FormState, MFormBox } from '@tmagic/form';
import type { CodeBlockContent } from '@tmagic/schema';

import FloatingBox from '@editor/components/FloatingBox.vue';
import CodeEditor from '@editor/layouts/CodeEditor.vue';
import type { Services, SlideType } from '@editor/type';
import { getConfig } from '@editor/utils/config';

defineOptions({
  name: 'MEditorCodeBlockEditor',
});

const props = defineProps<{
  content: CodeBlockContent;
  disabled?: boolean;
  isDataSource?: boolean;
  dataSourceType?: string;
  slideType?: SlideType;
}>();

const emit = defineEmits<{
  submit: [values: CodeBlockContent];
}>();

const services = inject<Services>('services');

const difVisible = ref(false);
const height = ref(globalThis.innerHeight);

const windowResizeHandler = () => {
  height.value = globalThis.innerHeight;
};

globalThis.addEventListener('resize', windowResizeHandler);

onBeforeUnmount(() => {
  globalThis.removeEventListener('resize', windowResizeHandler);
});

const magicVsEditor = ref<InstanceType<typeof CodeEditor>>();

const diffChange = () => {
  if (!magicVsEditor.value || !formBox.value?.form) {
    return;
  }

  formBox.value.form.values.content = magicVsEditor.value.getEditorValue();

  difVisible.value = false;
};

const columnWidth = computed(() => services?.uiService.get('columnWidth'));
const size = computed(() =>
  columnWidth.value ? columnWidth.value.center + columnWidth.value.right - (props.isDataSource ? 100 : 0) : 600,
);

const codeEditorHeight = ref('600px');

const defaultParamColConfig: ColumnConfig = {
  type: 'row',
  label: '参数类型',
  items: [
    {
      text: '参数类型',
      labelWidth: '70px',
      type: 'select',
      name: 'type',
      options: [
        {
          text: '数字',
          label: '数字',
          value: 'number',
        },
        {
          text: '字符串',
          label: '字符串',
          value: 'text',
        },
        {
          text: '组件',
          label: '组件',
          value: 'ui-select',
        },
      ],
    },
  ],
};

const functionConfig = computed<FormConfig>(() => [
  {
    text: '名称',
    name: 'name',
    rules: [{ required: true, message: '请输入名称', trigger: 'blur' }],
  },
  {
    text: '描述',
    name: 'desc',
  },
  {
    text: '执行时机',
    name: 'timing',
    type: 'select',
    options: () => {
      const options = [
        { text: '初始化前', value: 'beforeInit' },
        { text: '初始化后', value: 'afterInit' },
      ];
      if (props.dataSourceType !== 'base') {
        options.push({ text: '请求前', value: 'beforeRequest' });
        options.push({ text: '请求后', value: 'afterRequest' });
      }
      return options;
    },
    display: () => props.isDataSource,
  },
  {
    type: 'table',
    border: true,
    text: '参数',
    enableFullscreen: false,
    enableToggleMode: false,
    name: 'params',
    dropSort: false,
    items: [
      {
        type: 'text',
        label: '参数名',
        name: 'name',
      },
      {
        type: 'text',
        label: '描述',
        name: 'extra',
      },
      services?.codeBlockService.getParamsColConfig() || defaultParamColConfig,
    ],
  },
  {
    name: 'content',
    type: 'vs-code',
    options: inject('codeOptions', {}),
    height: codeEditorHeight.value,
    onChange: (formState: FormState | undefined, code: string) => {
      try {
        // 检测js代码是否存在语法错误
        getConfig('parseDSL')(code);

        return code;
      } catch (error: any) {
        tMagicMessage.error(error.message);

        throw error;
      }
    },
  },
]);

const submitForm = (values: CodeBlockContent) => {
  changedValue.value = undefined;
  emit('submit', values);
};

const errorHandler = (error: any) => {
  tMagicMessage.error(error.message);
};

const formBox = ref<InstanceType<typeof MFormBox>>();

const openHandler = () => {
  setTimeout(() => {
    if (formBox.value) {
      const height = formBox.value?.bodyHeight - 348 - (props.isDataSource ? 50 : 0);
      codeEditorHeight.value = `${height > 100 ? height : 600}px`;
    }
  });
};

const changedValue = ref<CodeBlockContent>();
const changeHandler = (values: CodeBlockContent) => {
  changedValue.value = values;
};

const beforeClose = (done: (cancel?: boolean) => void) => {
  if (!changedValue.value) {
    editVisible.value = false;
    done();
    return;
  }
  tMagicMessageBox
    .confirm('当前代码块已修改，是否保存？', '提示', {
      confirmButtonText: '保存并关闭',
      cancelButtonText: '不保存并关闭',
      type: 'warning',
      distinguishCancelAndClose: true,
    })
    .then(() => {
      changedValue.value && submitForm(changedValue.value);
      editVisible.value = false;
      done();
    })
    .catch((action: string) => {
      if (action === 'cancel') {
        editVisible.value = false;
      }
      done(action === 'cancel');
    });
};

const closedHandler = () => {
  changedValue.value = undefined;
};

const boxVisible = ref<boolean>(false);
const editVisible = ref<boolean>(false);
const floatingBoxBody = ref<HTMLDivElement>();

const boxPosition = computed(() => {
  const columnWidth = services?.uiService?.get('columnWidth');
  const navMenuRect = services?.uiService?.get('navMenuRect');
  return {
    left: columnWidth?.left ?? 0,
    top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
  };
});

defineExpose({
  async show() {
    if (props.slideType !== 'box') {
      boxVisible.value = true;
      await nextTick();
    }

    editVisible.value = true;
  },

  async hide() {
    editVisible.value = false;

    if (props.slideType !== 'box') {
      await nextTick();
      boxVisible.value = false;
    }
  },
});
</script>
