<script setup lang="ts">
import type { FormInstance } from 'element-plus';

import { computed, onUnmounted, ref, watch } from 'vue';

import { Position } from '@element-plus/icons-vue';
import { ElButton, ElForm, ElFormItem } from 'element-plus';

import { api } from '#/api/request';
import { $t } from '#/locales';

import WorkflowFormItem from './WorkflowFormItem.vue';

export type WorkflowFormProps = {
  onAsyncExecute?: (values: any) => void;
  onSubmit?: (values: any) => void;
  tinyFlowData: any;
  workflowId: any;
  workflowParams: any;
};
const props = withDefaults(defineProps<WorkflowFormProps>(), {
  onExecuting: () => {
    console.warn('no execute method');
  },
  onSubmit: () => {
    console.warn('no submit method');
  },
  onAsyncExecute: () => {
    console.warn('no async execute method');
  },
});
defineExpose({
  resume,
});
const runForm = ref<FormInstance>();
const runParams = ref<any>({});
const submitLoading = ref(false);
const startFormMeta = computed(() => {
  const meta = props.workflowParams?.startFormMeta || {};
  return {
    title:
      meta.title == null
        ? props.workflowParams?.title || ''
        : String(meta.title).trim(),
    description:
      meta.description == null
        ? props.workflowParams?.description || ''
        : String(meta.description).trim(),
    submitText: String(meta.submitText || '').trim() || $t('button.run'),
  };
});
const parameters = computed(() => {
  const schema = Array.isArray(props.workflowParams?.startFormSchema)
    ? props.workflowParams.startFormSchema
    : [];
  if (schema.length === 0) {
    return props.workflowParams.parameters || [];
  }
  return schema.map((field: any) => {
    const type = String(field.type || '').trim() || 'text';
    return {
      name: field.key,
      formLabel: field.label || field.key,
      formDescription: field.description || '',
      formPlaceholder: field.placeholder || '',
      required: Boolean(field.required),
      defaultValue: field.defaultValue,
      enums: Array.isArray(field.options) ? field.options : [],
      contentType: type === 'file' ? 'file' : 'text',
      formType: type === 'text' ? 'input' : type === 'file' ? 'input' : type,
      dataType:
        type === 'checkbox' ? 'Array' : type === 'file' ? 'File' : 'String',
    };
  });
});
watch(
  parameters,
  (items) => {
    const nextRunParams = { ...runParams.value };
    let changed = false;
    for (const item of items || []) {
      if (nextRunParams[item.name] !== undefined) {
        continue;
      }
      if (item.defaultValue !== undefined && item.defaultValue !== '') {
        nextRunParams[item.name] = item.defaultValue;
        changed = true;
        continue;
      }
      if (item.formType === 'checkbox') {
        nextRunParams[item.name] = [];
        changed = true;
        continue;
      }
      if (item.contentType === 'file') {
        nextRunParams[item.name] = [];
        changed = true;
      }
    }
    if (changed) {
      runParams.value = nextRunParams;
    }
  },
  {
    immediate: true,
    deep: true,
  },
);
const executeId = ref('');
function resume(data: any) {
  data.executeId = executeId.value;
  submitLoading.value = true;
  api.post('/api/v1/workflow/resume', data).then((res) => {
    if (res.errorCode === 0) {
      startPolling(executeId.value);
    }
  });
}
function submitV2() {
  runForm.value?.validate((valid) => {
    if (valid) {
      const data = {
        id: props.workflowId,
        variables: {
          ...runParams.value,
        },
      };
      props.onSubmit?.(runParams.value);
      submitLoading.value = true;
      api.post('/api/v1/workflow/runAsync', data).then((res) => {
        if (res.errorCode === 0 && res.data) {
          // executeId
          executeId.value = res.data;
          startPolling(res.data);
        }
      });
    }
  });
}
const timer = ref();
const nodes = ref(
  props.tinyFlowData.nodes.map((node: any) => ({
    nodeId: node.id,
    nodeName: node.data.title,
  })),
);
// 轮询执行结果
function startPolling(executeId: any) {
  if (timer.value) return;
  timer.value = setInterval(() => executePolling(executeId), 1000);
}
function executePolling(executeId: any) {
  api
    .post('/api/v1/workflow/getChainStatus', {
      executeId,
      nodes: nodes.value,
    })
    .then((res) => {
      // 5 是挂起状态
      if (res.data.status !== 1 || res.data.status === 5) {
        stopPolling();
      }
      props.onAsyncExecute?.(res.data);
    });
}
function stopPolling() {
  submitLoading.value = false;
  if (timer.value) {
    clearInterval(timer.value);
    timer.value = null;
  }
}
onUnmounted(() => {
  stopPolling();
});
</script>

<template>
  <div>
    <ElForm label-position="top" ref="runForm" :model="runParams">
      <div
        v-if="startFormMeta.title || startFormMeta.description"
        class="workflow-form__header"
      >
        <div v-if="startFormMeta.title" class="workflow-form__title">
          {{ startFormMeta.title }}
        </div>
        <div
          v-if="startFormMeta.description"
          class="workflow-form__description"
        >
          {{ startFormMeta.description }}
        </div>
      </div>
      <WorkflowFormItem
        v-model:run-params="runParams"
        :parameters="parameters"
      />
      <ElFormItem>
        <ElButton
          type="primary"
          @click="submitV2"
          :loading="submitLoading"
          :icon="Position"
        >
          {{ startFormMeta.submitText }}
        </ElButton>
      </ElFormItem>
    </ElForm>
  </div>
</template>

<style scoped>
.workflow-form__header {
  margin-bottom: 16px;
}

.workflow-form__title {
  font-size: 16px;
  font-weight: 600;
  color: var(--el-text-color-primary);
}

.workflow-form__description {
  margin-top: 6px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--el-text-color-secondary);
}
</style>
