<script lang="ts" setup>
import { nextTick, onUnmounted, reactive, ref, watch } from 'vue'
import { Button, Input, InputNumber, Switch, Tabs, Upload, message } from 'ant-design-vue'
import type { UploadFile } from 'ant-design-vue'
import RuntimeNodes from './RuntimeNodes.vue'
import SvgIcon from './SvgIcon.vue'
import { workflowRun, workflowRuntimeResume, getUploadAction,workflowApi } from '#/api/aiflow'
import { useWfStore } from '#/packages/workflow-designer/store'

interface Props {
  workflow: any;
}
interface TabObj {
  name: string;
  tab: string;
  defaultTab: string;
}
interface Emit {
  (e: 'runDone'): void;
  (e: 'runError', errorMsg: string): void;
}

const props = defineProps<Props>();
const emit = defineEmits<Emit>();
const headers: Record<string, string> = { Authorization: '' };
const wfStore = useWfStore();
const token = ref<string>('');
const submitting = ref<boolean>(wfStore.submitting);
const startNode = ref<any>(null);
const wfRuntimeUuid = ref<string>('');
const runtimeNodes = reactive<any[]>([]);
const runtimeErrorMsg = ref<string>('');
const userInputs = ref<any[]>([]);
const errorMsg = ref<string>('');
const currWfUuid = props.workflow.uuid;
const showCurrentExecution = ref<boolean>(false);
const tabObj = ref<TabObj>({
  name: 'runtimes',
  defaultTab: '流程执行详情',
  tab: '流程执行详情 ↓',
});
const fileListLength = ref(0);
const uploadRef = ref<any>(null);
const fileList = ref<UploadFile[]>([]);
const uploadedFileUuids = ref<string[]>([]);
const humanFeedback = ref<boolean>(false);
const humanFeedbackTip = ref<string>('');
const humanFeedbackContent = ref<string>('');
// 组件ID到组件名称的映射
const componentIdToNameMap = ref<Record<string, string>>({});
let controller = new AbortController()
function onKeydown(e: KeyboardEvent) {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    if (!submitting.value) run();
  }
}

async function uploadBeforeRun() {
  uploadedFileUuids.value = [];
  // Antd的Upload组件自动提交，无需手动调用submit
}

async function resetInputs() {
  fileList.value = [];
  uploadedFileUuids.value = [];
  userInputs.value.forEach((input: any) => {
    input.content.value = null;
  });
}

async function run() {
  if (submitting.value) return;

  for (const input of userInputs.value) {
    if (
      input.required &&
      input.content.type === 4 &&
      input.content.value === null &&
      fileListLength.value === 0
    ) {
      message.warning('请上传文件');
      return;
    }
  }

  if (
    fileListLength.value > 0 &&
    uploadedFileUuids.value.length !== fileListLength.value
  ) {
    uploadBeforeRun();
    return;
  } else {
    // 若存在文件输入但未走上传控件回调，直接将已上传的uuid写入
    const fileInput = userInputs.value.find(
      (input: any) => input.content.type === 4,
    );
    if (
      fileInput &&
      (!fileInput.content.value || fileInput.content.value.length === 0)
    ) {
      fileInput.content.value = uploadedFileUuids.value;
    }
  }

  if (
    userInputs.value.some(
      (input: any) => input.required && input.content.value === null,
    )
  ) {
    message.warning('请输入所有必填参数');
    return;
  }

  submitting.value = true;
  showCurrentExecution.value = true;
  tabObj.value.tab = showCurrentExecution.value
    ? `${tabObj.value.defaultTab} ↓`
    : `${tabObj.value.defaultTab} ↑`;

  controller = new AbortController();
  try {
    wfRuntimeUuid.value = '';
    const nodeUuidToRuntimeNodeUuid = new Map<string, string>();
    runtimeNodes.splice(0, runtimeNodes.length);
    await workflowRun({
      options: { uuid: currWfUuid, inputs: userInputs.value },
      signal: controller.signal,
      startCallback: (wfRuntimeJson) => {
        if (!wfRuntimeJson) {
          message.error('启动失败');
          return;
        }
        const wfRuntime = JSON.parse(wfRuntimeJson);
        wfRuntime.input = {};
        userInputs.value.forEach((item: any) => {
          wfRuntime.input[item.name] = { ...item.content };
        });
        wfRuntimeUuid.value = wfRuntime.uuid;
        wfStore.appendWfRuntimes(currWfUuid, [wfRuntime]);
      },
      thinkingDataReceived: (chunk) => {
        console.log('Thinking data received:', chunk);
      },
      messageReceived: (chunk, event) => {
        const eventName = event || '';
        try {
          if (eventName.includes('[NODE_RUN_')) {
            const nodeUuid = eventName
              .replace('[NODE_RUN_', '')
              .replace(']', '');
            const runtimeNode = JSON.parse(chunk);
            nodeUuidToRuntimeNodeUuid.set(nodeUuid, runtimeNode.uuid);
            // 补充节点元信息（标题、组件），用于 UI 展示
            const wfNodeMeta = (props.workflow?.nodes || []).find(
              (n: any) => n.uuid === nodeUuid,
            );
            if (wfNodeMeta) {
              (runtimeNode as any).nodeTitle = wfNodeMeta.title;
              // 设置组件信息，支持两种数据结构
              if (wfNodeMeta.wfComponent) {
                (runtimeNode as any).wfComponent = wfNodeMeta.wfComponent;
              } else if (wfNodeMeta.workflowComponentId) {
                (runtimeNode as any).workflowComponentId =
                  wfNodeMeta.workflowComponentId;
              }
            }
            wfStore.appendRuntimeNode(wfRuntimeUuid.value, runtimeNode);
            runtimeNodes.push(runtimeNode);
          } else if (eventName.includes('[NODE_CHUNK_')) {
            console.log('NODE_CHUNK_', eventName, chunk);
            const nodeUuid = eventName
              .replace('[NODE_CHUNK_', '')
              .replace(']', '');
            const runtimeNodeUuid =
              nodeUuidToRuntimeNodeUuid.get(nodeUuid) || '';
            wfStore.appendChunkToRuntimeNode(
              wfRuntimeUuid.value,
              runtimeNodeUuid,
              chunk,
            );
            const hit = runtimeNodes.find(
              (n: any) => n.uuid === runtimeNodeUuid,
            );
            if (hit) {
              (hit as any).chunks = ((hit as any).chunks || '') + chunk;
            }
          } else if (eventName.includes('[NODE_INPUT_')) {
            const nodeUuid = eventName
              .replace('[NODE_INPUT_', '')
              .replace(']', '');
            const runtimeNodeUuid =
              nodeUuidToRuntimeNodeUuid.get(nodeUuid) || '';
            wfStore.appendInputToRuntimeNode(
              wfRuntimeUuid.value,
              runtimeNodeUuid,
              chunk,
            );
            const hit = runtimeNodes.find(
              (n: any) => n.uuid === runtimeNodeUuid,
            );
            if (hit) {
              const payload = JSON.parse(chunk);
              (hit as any).input = {
                ...(hit as any).input,
                [payload.name]: payload.content,
              };
            }
          } else if (eventName.includes('[NODE_OUTPUT_')) {
            const nodeUuid = eventName
              .replace('[NODE_OUTPUT_', '')
              .replace(']', '');
            const runtimeNodeUuid =
              nodeUuidToRuntimeNodeUuid.get(nodeUuid) || '';
            wfStore.appendOutputToRuntimeNode(
              wfRuntimeUuid.value,
              runtimeNodeUuid,
              chunk,
            );
            const hit = runtimeNodes.find(
              (n: any) => n.uuid === runtimeNodeUuid,
            );
            if (hit) {
              const payload = JSON.parse(chunk);
              (hit as any).output = {
                ...(hit as any).output,
                [payload.name]: payload.content,
              };
            }
          } else if (eventName.includes('[NODE_WAIT_FEEDBACK_BY_')) {
            humanFeedback.value = true;
            humanFeedbackTip.value = chunk || '';
            message.info(humanFeedbackTip.value);
          }
        } catch (error) {
          console.error(error);
        }
      },
      doneCallback: (chunk) => {
        nextTick(() => {
          submitting.value = false;
          resetInputs();
          wfStore.updateSuccess(currWfUuid, wfRuntimeUuid.value, chunk);
          runtimeErrorMsg.value = '';
          message.success('执行成功');
          emit('runDone');
        });
      },
      errorCallback: (error) => {
        submitting.value = false;
        resetInputs();
        message.error(`系统提示：${error}`);
        wfStore.updateErrorMsg(currWfUuid, wfRuntimeUuid.value, error);
        runtimeErrorMsg.value = error || '';
        emit('runError', error);
      },
    });
  } catch (error: any) {
    const errorMessage = error?.message ?? '执行出错';
    message.error(errorMessage);
    submitting.value = false;
  }
}

async function resume() {
  submitting.value = true;
  try {
    await workflowRuntimeResume({
      runtimeUuid: wfRuntimeUuid.value,
      feedbackContent: humanFeedbackContent.value,
    });
  } catch (e) {
    message.error(`系统提示：${e}`);
  } finally {
    humanFeedback.value = false;
    humanFeedbackTip.value = '';
    humanFeedbackContent.value = '';
  }
}

async function handleFileListChange(info: any) {
  const ret = await workflowApi.uploadFile(info.file.originFileObj);

  if (ret?.uploadVos && ret.uploadVos.length) {
    info.file.status = 'done';
    fileList.value = info.fileList;
    fileListLength.value = info.fileList.length;
    uploadedFileUuids.value.push(ret.uploadVos[0].filePath);
      if (uploadedFileUuids.value.length === fileListLength.value) {
        run();
      }
  }

  // console.log('info', info, uploadedFileUuids);
  // if (info.file.status === 'done') {
  //   const res = info.file.response;
  //   if (res && res.success) {
  //     uploadedFileUuids.value.push(res.data.uuid);
  //     if (uploadedFileUuids.value.length === fileListLength.value) {
  //       run();
  //     }
  //   }
  // }
}

function handleStop() {
  if (wfStore.wfUuidToWfRuntimeLoading.get(currWfUuid)) controller.abort();
  submitting.value = false;
}

function handleClick() {
  showCurrentExecution.value = !showCurrentExecution.value;
  tabObj.value.tab = showCurrentExecution.value
    ? `${tabObj.value.defaultTab} ↓`
    : `${tabObj.value.defaultTab} ↑`;
}

// function findStartNodeFromWorkflow() {
//   return Array.isArray(props.workflow?.nodes)
//     ? props.workflow.nodes.find((n: any) => {
//         // 优先检查 wfComponent.name（编辑时的数据结构）
//         if (n?.wfComponent?.name === 'Start') return true;
//         // 检查 workflowComponentId（后端返回的数据结构）
//         // 后端返回的是字符串，需要转换为数字比较
//         if (Number(n?.workflowComponentId) === 1) return true;
//         return false;
//       })
//     : null
// }

// 根据 workflowComponentId 获取组件名称
function getComponentNameByWorkflowComponentId(
  workflowComponentId: number | string,
): string {
  const id = String(workflowComponentId);
  return componentIdToNameMap.value[id] || 'Unknown';
}
function findStartNodeFromWorkflow() {
  return Array.isArray(props.workflow?.nodes)
    ? props.workflow.nodes.find((n: any) => {
        // 优先检查 wfComponent.name（编辑时的数据结构）
        if (n?.wfComponent?.name === 'Start') return true;
        // 检查 workflowComponentId（后端返回的数据结构）
        // 使用映射函数判断组件类型
        if (n?.workflowComponentId !== undefined) {
          const componentName = getComponentNameByWorkflowComponentId(
            n.workflowComponentId,
          );
          if (componentName === 'Start') return true;
        }
        // 备用方案：检查节点标题是否包含"开始"
        if (n?.title && (n.title === '开始' || n.title.includes('开始'))) {
          return true;
        }
        return false;
      })
    : null;
}

function rebuildUserInputs() {
  const storeStart = wfStore.getStartNode(props.workflow.uuid)
  const localStart = findStartNodeFromWorkflow()
  startNode.value = storeStart || localStart || null
  if (startNode.value && Array.isArray(startNode.value.inputConfig?.user_inputs)) {
    userInputs.value = startNode.value.inputConfig.user_inputs.map((input: any) => ({
      uuid: input.uuid,
      name: input.name,
      content: { title: input.title, value: null, type: input.type },
      required: input.required,
    }))
  } else {
    userInputs.value = [];
  }
}
// 获取组件列表并构建映射
async function fetchWorkflowComponents() {
  try {
    const response = await workflowApi.workflowComponents();
    // 处理可能的响应格式：可能是直接数组，也可能是包装对象
    const components = Array.isArray(response)
      ? response
      : response?.data || [];
    const map: Record<string, string> = {};
    if (Array.isArray(components)) {
      components.forEach((component: any) => {
        // 使用 id 作为 key，name 作为 value
        const id = String(component.id);
        map[id] = component.name;
      });
    }
    componentIdToNameMap.value = map;
    console.log('组件ID映射:', map);
  } catch (error) {
    console.error('获取组件列表失败:', error);
    // 如果获取失败，使用空映射，后续会使用备用方案
    componentIdToNameMap.value = {};
  }
}
// 初始化：获取组件列表并重建用户输入
async function init() {
  await fetchWorkflowComponents();
  rebuildUserInputs();
}

init();

watch(() => props.workflow, () => rebuildUserInputs(), { deep: true })

headers.Authorization = token.value;
onUnmounted(() => {
  if (wfStore.wfUuidToWfRuntimeLoading.get(currWfUuid)) controller.abort();
});
</script>

<template>
  <div class="z-10 m-auto w-full max-w-screen-xl" @keydown="onKeydown">
    <Tabs :active-key="tabObj.name" type="line" @click="handleClick">
      <Tabs.TabPane key="runtimes" :tab="tabObj.tab" />
    </Tabs>
    <transition name="collapse">
      <div
        v-show="showCurrentExecution"
        class="mb-2 max-h-[500px] overflow-y-auto"
      >
        <RuntimeNodes
          :nodes="runtimeNodes"
          :workflow="workflow"
          :error-msg="runtimeErrorMsg"
          :token="token"
        />
        <div class="sticky bottom-0 left-0 flex justify-center">
          <Button v-show="submitting" size="small" @click="handleStop">
            <template #icon><SvgIcon icon="ri:stop-circle-line" /></template>
            停止请求
          </Button>
        </div>
      </div>
    </transition>
    <div v-if="errorMsg">{{ errorMsg }}</div>
    <div
      class="flex max-h-[300px] flex-col items-center justify-between space-y-2 overflow-y-auto"
    >
      <template v-if="!humanFeedback">
        <div
          v-for="(userInput, idx) in userInputs"
          :key="`${idx}_${userInput.name}`"
          class="flex w-full"
        >
          <div class="min-w-24">{{ userInput.content.title }}</div>
          <Input.TextArea
            v-if="userInput.content.type === 1"
            v-model:value="userInput.content.value"
            :auto-size="{ minRows: 1, maxRows: 5 }"
          />
          <InputNumber
            v-if="userInput.content.type === 2"
            v-model:value="userInput.content.value"
            class="w-full"
          />
          <div v-if="userInput.content.type === 3" />
<Upload v-if="userInput.content.type === 4" ref="uploadRef" multiple :max-count="startNode?.inputConfig.user_inputs.find((item: any) => item.uuid === userInput.uuid)?.limit || 10" :headers="headers" :file-list="fileList" @change="handleFileListChange">
          <!-- <Upload v-if="userInput.content.type === 4" ref="uploadRef" multiple :action="getUploadAction()" :max-count="startNode?.inputConfig.user_inputs.find((item: any) => item.uuid === userInput.uuid)?.limit || 10" :headers="headers" :file-list="fileList" @change="handleFileListChange"> -->
            <!-- <Upload.Dragger> -->
              <div style="font-size: 16px">点击或者拖动文件到该区域来上传</div>
              <div style="margin: 4px 0 0 0; color: #999">文件格式: TXT、PDF、DOC、DOCX、XLS、XLXS、PPT、PPTX；文件大小：不超过10M</div>
            <!-- </Upload.Dragger> -->
          </Upload>
          <Switch
            v-if="userInput.content.type === 5"
            v-model:checked="userInput.content.value"
          />
        </div>
        <div
          class="flex w-full items-center justify-between text-xs text-gray-400"
          @keydown.enter="run"
        >
          <div>按 Enter 提交，Shift + Enter 换行</div>
          <Button
            type="primary"
            :disabled="submitting"
            :loading="submitting"
            @click="run"
            >提交</Button
          >
        </div>
      </template>
      <template v-if="humanFeedback">
        <div class="flex w-full flex-col space-y-2 p-2">
          <div class="flex rounded-md bg-gray-100 px-2 py-1">
            <div class="text-base text-red-500">
              流程已暂停，等待用户输入中...
            </div>
          </div>
          <div class="flex w-full flex-col">
            <div v-if="humanFeedbackTip" class="text-sm leading-8">
              提示：{{ humanFeedbackTip }}
            </div>
            <Input.TextArea
              v-model:value="humanFeedbackContent"
              :auto-size="{ minRows: 2, maxRows: 5 }"
            />
          </div>
          <div class="flex justify-end">
            <Button type="primary" @click="resume">提交</Button>
          </div>
        </div>
      </template>
    </div>
  </div>
</template>
