<script lang="ts" setup>
import { inject, nextTick, onMounted, ref, toRaw, watch } from 'vue';

import { confirm, useVbenModal } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';

import {
  ElButton,
  ElDivider,
  ElForm,
  ElFormItem,
  ElInput,
  ElOption,
  ElSelect,
  ElSwitch,
} from 'element-plus';

import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getModelList } from '#/api/bpm/model';

interface FormData {
  processInstanceName: string;
  calledElement: string;
  inheritVariables: boolean;
  businessKey: string;
  inheritBusinessKey: boolean;
  calledElementType: string;
}

defineOptions({ name: 'CallActivity' });
const props = defineProps({
  id: { type: String, default: '' },
  type: { type: String, default: '' },
});
const prefix = inject('prefix');

const formData = ref<FormData>({
  processInstanceName: '',
  calledElement: '',
  inheritVariables: false,
  businessKey: '',
  inheritBusinessKey: false,
  calledElementType: 'key',
});
const inVariableList = ref<any[]>([]);
const outVariableList = ref<any[]>([]);
const variableType = ref<string>(); // 参数类型
const editingVariableIndex = ref<number>(-1); // 编辑参数下标
const varialbeFormRef = ref();
const varialbeFormData = ref<{
  source: string;
  target: string;
}>({
  source: '',
  target: '',
});

const bpmnInstances = () => (window as any)?.bpmnInstances;
const bpmnElement = ref<any>();
const otherExtensionList = ref<any[]>([]);
const childProcessOptions = ref<{ key: string; name: string }[]>([]);

const initCallActivity = () => {
  bpmnElement.value = bpmnInstances().bpmnElement;

  // 初始化所有配置项
  Object.keys(formData.value).forEach((key: string) => {
    // @ts-ignore
    formData.value[key] =
      bpmnElement.value.businessObject[key] ??
      formData.value[key as keyof FormData];
  });

  otherExtensionList.value = []; // 其他扩展配置
  inVariableList.value.length = 0;
  outVariableList.value.length = 0;
  // 初始化输入参数
  bpmnElement.value.businessObject?.extensionElements?.values?.forEach(
    (ex: any) => {
      if (ex.$type === `${prefix}:In`) {
        inVariableList.value.push(ex);
      } else if (ex.$type === `${prefix}:Out`) {
        outVariableList.value.push(ex);
      } else {
        otherExtensionList.value.push(ex);
      }
    },
  );
};

const updateCallActivityAttr = (attr: keyof FormData) => {
  bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
    [attr]: formData.value[attr],
  });
};

const [VariableModal, variableModalApi] = useVbenModal({
  title: '参数配置',
  onConfirm: () => {
    saveVariable();
  },
});

const openVariableForm = (type: string, data: any, index: number) => {
  editingVariableIndex.value = index;
  variableType.value = type;
  varialbeFormData.value = index === -1 ? {} : { ...data };
  variableModalApi.open();
};

const removeVariable = async (type: string, index: number) => {
  try {
    await confirm({
      title: '提示',
      content: '是否确认删除？',
    });
    if (type === 'in') {
      inVariableList.value.splice(index, 1);
    }
    if (type === 'out') {
      outVariableList.value.splice(index, 1);
    }
    updateElementExtensions();
  } catch (error: any) {
    console.error(`[removeVariable error ]: ${error.message || error}`);
  }
};

const saveVariable = async () => {
  try {
    await varialbeFormRef.value?.validate();
  } catch {
    // 验证失败直接返回
    return;
  }

  if (editingVariableIndex.value === -1) {
    if (variableType.value === 'in') {
      inVariableList.value.push(
        bpmnInstances().moddle.create(`${prefix}:In`, {
          ...varialbeFormData.value,
        }),
      );
    }
    if (variableType.value === 'out') {
      outVariableList.value.push(
        bpmnInstances().moddle.create(`${prefix}:Out`, {
          ...varialbeFormData.value,
        }),
      );
    }
    updateElementExtensions();
  } else {
    if (variableType.value === 'in') {
      inVariableList.value[editingVariableIndex.value].source =
        varialbeFormData.value.source;
      inVariableList.value[editingVariableIndex.value].target =
        varialbeFormData.value.target;
    }
    if (variableType.value === 'out') {
      outVariableList.value[editingVariableIndex.value].source =
        varialbeFormData.value.source;
      outVariableList.value[editingVariableIndex.value].target =
        varialbeFormData.value.target;
    }
  }
  variableModalApi.close();
};

const updateElementExtensions = () => {
  const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
    values: [
      ...inVariableList.value,
      ...outVariableList.value,
      ...otherExtensionList.value,
    ],
  });
  bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
    extensionElements: extensions,
  });
};

watch(
  () => props.id,
  (val) => {
    val &&
      val.length > 0 &&
      nextTick(() => {
        initCallActivity();
      });
  },
  { immediate: true },
);

const gridOptions = {
  columns: [
    { title: '源', field: 'source', minWidth: 100 },
    { title: '目标', field: 'target', minWidth: 100 },
    {
      title: '操作',
      width: 130,
      slots: { default: 'action' },
      fixed: 'right' as const,
    },
  ],
  border: true,
  showOverflow: true,
  height: 'auto',
  toolbarConfig: { enabled: false },
  pagerConfig: { enabled: false },
};

const [InVariableGrid, inVariableGridApi] = useVbenVxeGrid({
  gridOptions,
});

const [OutVariableGrid, outVariableGridApi] = useVbenVxeGrid({
  gridOptions,
});

// 使用浅层监听，避免无限循环
watch(
  () => [...inVariableList.value],
  (val) => {
    inVariableGridApi.setGridOptions({ data: val });
  },
);

watch(
  () => [...outVariableList.value],
  (val) => {
    outVariableGridApi.setGridOptions({ data: val });
  },
);

/** 选择子流程, 更新 bpmn callActivity calledElement 和 processInstanceName 属性 */
const handleChildProcessChange = (key: any) => {
  if (!key) return;
  const selected = childProcessOptions.value.find((item) => item.key === key);
  if (selected) {
    formData.value.calledElement = selected.key;
    formData.value.processInstanceName = selected.name;
    updateCallActivityAttr('calledElement');
    updateCallActivityAttr('processInstanceName');
  }
};

onMounted(async () => {
  try {
    // 获取流程模型列表
    const list = await getModelList(undefined);
    childProcessOptions.value = list.map((item) => ({
      key: item.key,
      name: item.name,
    }));
  } catch (error) {
    console.error('获取子流程列表失败', error);
  }
});
</script>

<template>
  <div class="-mx-2">
    <ElForm label-width="100px">
      <ElFormItem label="被调用子流程">
        <ElSelect
          v-model="formData.calledElement"
          placeholder="请选择子流程"
          clearable
          @change="handleChildProcessChange"
        >
          <ElOption
            v-for="item in childProcessOptions"
            :key="item.key"
            :value="item.key"
            :label="item.name"
          />
        </ElSelect>
      </ElFormItem>

      <ElFormItem label="继承变量">
        <ElSwitch
          v-model="formData.inheritVariables"
          @change="updateCallActivityAttr('inheritVariables')"
        />
      </ElFormItem>

      <ElFormItem label="继承业务键">
        <ElSwitch
          v-model="formData.inheritBusinessKey"
          @change="updateCallActivityAttr('inheritBusinessKey')"
        />
      </ElFormItem>

      <ElFormItem v-if="!formData.inheritBusinessKey" label="业务键表达式">
        <ElInput
          v-model="formData.businessKey"
          clearable
          placeholder="请输入业务键表达式"
          @change="updateCallActivityAttr('businessKey')"
        />
      </ElFormItem>

      <div
        class="mb-1 mt-2 flex items-center justify-between border-t border-gray-200 pt-2"
      >
        <span class="flex items-center text-sm font-medium"> 输入参数 </span>
        <ElButton
          class="flex items-center"
          size="small"
          type="primary"
          link
          @click="openVariableForm('in', null, -1)"
        >
          <template #icon>
            <IconifyIcon icon="ep:plus" />
          </template>
          添加参数
        </ElButton>
      </div>
      <InVariableGrid class="-mx-2 mb-4">
        <template #action="{ row, rowIndex }">
          <ElButton
            size="small"
            type="primary"
            link
            @click="openVariableForm('in', row, rowIndex)"
          >
            编辑
          </ElButton>
          <ElDivider direction="vertical" />
          <ElButton
            size="small"
            type="danger"
            link
            @click="removeVariable('in', rowIndex)"
          >
            移除
          </ElButton>
        </template>
      </InVariableGrid>

      <div
        class="mb-1 mt-2 flex items-center justify-between border-t border-gray-200 pt-2"
      >
        <span class="flex items-center text-sm font-medium"> 输出参数 </span>
        <ElButton
          class="flex items-center"
          size="small"
          type="primary"
          link
          @click="openVariableForm('out', null, -1)"
        >
          <template #icon>
            <IconifyIcon icon="lucide:plus" class="size-4" />
          </template>
          添加参数
        </ElButton>
      </div>
      <OutVariableGrid class="-mx-2">
        <template #action="{ row, rowIndex }">
          <ElButton
            size="small"
            type="primary"
            link
            @click="openVariableForm('out', row, rowIndex)"
          >
            编辑
          </ElButton>
          <ElDivider direction="vertical" />
          <ElButton
            size="small"
            type="danger"
            link
            @click="removeVariable('out', rowIndex)"
          >
            移除
          </ElButton>
        </template>
      </OutVariableGrid>
    </ElForm>

    <VariableModal>
      <ElForm
        :model="varialbeFormData"
        ref="varialbeFormRef"
        label-width="60px"
      >
        <ElFormItem
          label="源"
          prop="source"
          :rules="[
            {
              required: true,
              message: '源不能为空',
              trigger: ['blur', 'change'],
            },
          ]"
        >
          <ElInput v-model="varialbeFormData.source" clearable />
        </ElFormItem>
        <ElFormItem
          label="目标"
          prop="target"
          :rules="[
            {
              required: true,
              message: '目标不能为空',
              trigger: ['blur', 'change'],
            },
          ]"
        >
          <ElInput v-model="varialbeFormData.target" clearable />
        </ElFormItem>
      </ElForm>
    </VariableModal>
  </div>
</template>
