<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';
import { resolveWorkflowFormParameters } from './workflowFormParameters';

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(() =>
  resolveWorkflowFormParameters(props.workflowParams),
);
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 POLLING_INTERVAL_MS = 1000;
const timer = ref<null | ReturnType<typeof setTimeout>>(null);
let pollingActive = false;
let pollingGeneration = 0;
const nodes = ref(
  props.tinyFlowData.nodes.map((node: any) => ({
    nodeId: node.id,
    nodeName: node.data.title,
  })),
);
// 轮询执行结果
function startPolling(executeId: any) {
  if (pollingActive) return;
  pollingActive = true;
  pollingGeneration += 1;
  schedulePolling(executeId, pollingGeneration);
}
function schedulePolling(executeId: any, generation: number) {
  timer.value = setTimeout(() => {
    timer.value = null;
    void executePolling(executeId, generation);
  }, POLLING_INTERVAL_MS);
}
async function executePolling(executeId: any, generation: number) {
  try {
    const res = await api.post('/api/v1/workflow/getChainStatus', {
      executeId,
      nodes: nodes.value,
    });
    if (!pollingActive || generation !== pollingGeneration) return;

    // 5 是挂起状态；所有非运行态都结束当前轮询。
    if (res.data.status !== 1) {
      stopPolling();
    }
    props.onAsyncExecute?.(res.data);

    if (pollingActive && generation === pollingGeneration) {
      schedulePolling(executeId, generation);
    }
  } catch (error) {
    if (!pollingActive || generation !== pollingGeneration) return;
    stopPolling();
    console.error('工作流状态轮询失败', error);
  }
}
function stopPolling() {
  submitLoading.value = false;
  pollingActive = false;
  pollingGeneration += 1;
  if (timer.value) {
    clearTimeout(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>
