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

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

import {
  CircleCloseFilled,
  SuccessFilled,
  VideoPause,
  WarningFilled,
} from '@element-plus/icons-vue';
import {
  ElAlert,
  ElButton,
  ElCollapse,
  ElCollapseItem,
  ElForm,
  ElFormItem,
  ElIcon,
} from 'element-plus';

import ShowJson from '#/components/json/ShowJson.vue';
import { $t } from '#/locales';
import ConfirmItem from '#/views/ai/workflow/components/ConfirmItem.vue';
import ConfirmItemMulti from '#/views/ai/workflow/components/ConfirmItemMulti.vue';

export interface WorkflowStepsProps {
  workflowId: any;
  nodeJson: any;
  initSignal?: boolean;
  pollingData?: any;
  expandAll?: boolean;
}
const props = defineProps<WorkflowStepsProps>();
const emit = defineEmits(['resume']);
const nodes = ref<any[]>([]);
const nodeStatusMap = ref<Record<string, any>>({});
const isChainError = ref(false);
const activeName = ref<any>(props.expandAll ? [] : '');
const confirmParams = ref<any>({});
// 定义一个对象来存储所有的 form 实例，key 为 node.key
const formRefs = ref<Record<string, FormInstance>>({});
const confirmBtnLoading = ref(false);
const chainErrMsg = ref('');

function shouldAutoExpandStatus(status: unknown) {
  return [1, 5, 20, 21].includes(Number(status));
}

function isExpandedNode(nodeKey: string) {
  if (Array.isArray(activeName.value)) {
    return activeName.value.includes(nodeKey);
  }
  return activeName.value === nodeKey;
}

function hasNodePayloadChanged(previous: any, current: any) {
  if (previous === current) {
    return false;
  }
  return JSON.stringify(previous ?? null) !== JSON.stringify(current ?? null);
}

function hasNodeStateChanged(previous: any, current: any) {
  if (!previous) {
    return true;
  }
  if ((previous?.status || null) !== (current?.status || null)) {
    return true;
  }
  if ((previous?.message || '') !== (current?.message || '')) {
    return true;
  }
  if (hasNodePayloadChanged(previous?.result, current?.result)) {
    return true;
  }
  return hasNodePayloadChanged(
    previous?.suspendForParameters,
    current?.suspendForParameters,
  );
}

watch(
  () => props.pollingData,
  (newVal) => {
    if (!newVal) {
      return;
    }
    const currentNodes = newVal.nodes || {};
    if (newVal.status === 21) {
      isChainError.value = true;
      chainErrMsg.value = newVal.message;
    }
    if (![20, 21].includes(newVal.status)) {
      confirmBtnLoading.value = false;
    }
    for (const nodeId in currentNodes) {
      const previousNodeState = nodeStatusMap.value[nodeId];
      const currentNodeState = currentNodes[nodeId];
      const previousStatus = previousNodeState?.status;
      const currentStatus = currentNodeState?.status;
      if (!hasNodeStateChanged(previousNodeState, currentNodeState)) {
        continue;
      }
      nodeStatusMap.value[nodeId] = currentNodeState;
      if (
        !props.expandAll &&
        previousStatus !== currentStatus &&
        shouldAutoExpandStatus(currentStatus)
      ) {
        activeName.value = nodeId;
      }
    }
  },
  { deep: true },
);
watch(
  () => props.initSignal,
  () => {
    nodeStatusMap.value = {};
    isChainError.value = false;
    confirmBtnLoading.value = false;
    chainErrMsg.value = '';
    activeName.value = props.expandAll ? [] : '';
  },
);
watch(
  () => props.nodeJson,
  (newVal) => {
    const nextNodes = Array.isArray(newVal) ? [...newVal] : [];
    nodes.value = nextNodes;
    activeName.value = props.expandAll
      ? nextNodes.map((node: any) => node.key)
      : '';
  },
  { immediate: true },
);
const displayNodes = computed(() => {
  return nodes.value.map((node) => ({
    ...node,
    ...nodeStatusMap.value[node.key],
  }));
});
// 动态设置 Ref 的辅助函数
const setFormRef = (el: any, key: string) => {
  if (el) {
    formRefs.value[key] = el as FormInstance;
  }
};
function getSelectMode(ops: any) {
  return ops.formType || 'radio';
}
function handleConfirm(node: any) {
  const nodeKey = node.key;
  // 根据 key 获取具体的 form 实例
  const form = formRefs.value[nodeKey];

  if (!form) {
    console.warn(`Form instance for ${nodeKey} not found`);
    return;
  }
  const confirmKey = node.suspendForParameters[0].name;
  form.validate((valid) => {
    if (valid) {
      const value = {
        confirmParams: {
          [confirmKey]: 'yes',
          ...confirmParams.value,
        },
      };
      confirmBtnLoading.value = true;
      emit('resume', value);
    }
  });
}
</script>

<template>
  <div>
    <div class="mb-1">
      <ElAlert v-if="chainErrMsg" :title="chainErrMsg" type="error" />
    </div>
    <ElCollapse
      v-model="activeName"
      :accordion="!props.expandAll"
      expand-icon-position="left"
    >
      <ElCollapseItem
        v-for="node in displayNodes"
        :key="node.key"
        :title="`${node.label}-${node.status}`"
        :name="node.key"
      >
        <template #title>
          <div class="flex items-center justify-between">
            <div>
              {{ node.label }}
            </div>
            <div class="flex items-center">
              <ElIcon
                v-if="node.status === 20 && !isChainError"
                color="green"
                size="20"
              >
                <SuccessFilled />
              </ElIcon>
              <div v-if="node.status === 1" class="spinner"></div>
              <ElIcon
                v-if="node.status === 21 && !isChainError"
                color="red"
                size="20"
              >
                <CircleCloseFilled />
              </ElIcon>
              <ElIcon
                v-if="node.status === 5 && !isChainError"
                color="orange"
                size="20"
              >
                <VideoPause />
              </ElIcon>
              <ElIcon v-if="isChainError" color="orange" size="20">
                <WarningFilled />
              </ElIcon>
            </div>
          </div>
        </template>
        <template v-if="isExpandedNode(node.key)">
          <div v-if="node.original.type === 'confirmNode'" class="p-2.5">
            <div class="mb-2 text-[16px] font-bold">
              {{ node.original.data.message }}
            </div>
            <ElForm
              :ref="(el) => setFormRef(el, node.key)"
              label-position="top"
              :model="confirmParams"
            >
              <template
                v-for="(ops, idx) in node.suspendForParameters"
                :key="idx"
              >
                <div class="header-container" v-if="ops.formType !== 'confirm'">
                  <div class="blue-bar">&nbsp;</div>
                  <span>{{ ops.formLabel || $t('message.confirmItem') }}</span>
                </div>
                <div
                  class="description-container"
                  v-if="ops.formType !== 'confirm'"
                >
                  {{ ops.formDescription }}
                </div>
                <ElFormItem
                  v-if="ops.formType !== 'confirm'"
                  :prop="ops.name"
                  :rules="[{ required: true, message: $t('message.required') }]"
                >
                  <ConfirmItem
                    v-if="getSelectMode(ops) === 'radio'"
                    v-model="confirmParams[ops.name]"
                    :selection-data-type="ops.contentType || 'text'"
                    :selection-data="ops.enums"
                  />
                  <ConfirmItemMulti
                    v-else
                    v-model="confirmParams[ops.name]"
                    :selection-data-type="ops.contentType || 'text'"
                    :selection-data="ops.enums"
                  />
                </ElFormItem>
              </template>
              <ElFormItem v-if="node.suspendForParameters?.length > 0">
                <div class="flex justify-end">
                  <ElButton
                    :disabled="confirmBtnLoading"
                    type="primary"
                    @click="handleConfirm(node)"
                  >
                    {{ $t('button.confirm') }}
                  </ElButton>
                </div>
              </ElFormItem>
            </ElForm>
          </div>
          <div v-else>
            <ShowJson :value="node.result || node.message" />
          </div>
        </template>
      </ElCollapseItem>
    </ElCollapse>
  </div>
</template>

<style scoped>
.spinner {
  width: 18px;
  height: 18px;
  border: 2px solid rgb(255 255 255 / 30%);
  border-top-color: var(--el-color-primary);
  border-right-color: var(--el-color-primary);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.header-container {
  display: flex;
  align-items: center;
  font-weight: bold;
  word-break: break-all;
}

.blue-bar {
  display: inline-block;
  width: 2px;
  height: 16px;
  margin-right: 16px;
  background-color: var(--el-color-primary);
  border-radius: 1px;
}

.description-container {
  margin-bottom: 16px;
  color: #969799;
  word-break: break-all;
}
</style>
