<script setup lang="ts">
import type { AiLlm, BotInfo } from '@easyflow/types';

import { computed, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';

import { $t } from '@easyflow/locales';
import { useBotStore } from '@easyflow/stores';

import {
  CopyDocument,
  Delete,
  InfoFilled,
  Link,
  Plus,
  Setting,
} from '@element-plus/icons-vue';
import { useDebounceFn } from '@vueuse/core';
import {
  ElAlert,
  ElAvatar,
  ElButton,
  ElCol,
  ElCollapse,
  ElCollapseItem,
  ElIcon,
  ElInput,
  ElInputNumber,
  ElMessage,
  ElMessageBox,
  ElOption,
  ElRow,
  ElSelect,
  ElSkeleton,
  ElSlider,
  ElSwitch,
  ElTag,
  ElTooltip,
} from 'element-plus';
import { tryit } from 'radash';

import {
  getPerQuestions,
  submitBotDeleteApproval,
  submitBotOfflineApproval,
  submitBotPublishApproval,
  updateBotApi,
  updateBotOptions,
  updateLlmId,
  updateLlmOptions,
} from '#/api';
import { api } from '#/api/request';
import ProblemPresupposition from '#/components/chat/ProblemPresupposition.vue';
import PublishWxOfficalAccount from '#/components/chat/PublishWxOfficalAccount.vue';
import CollapseViewItem from '#/components/collapseViewItem/CollapseViewItem.vue';
import CommonSelectDataModal from '#/components/commonSelectModal/CommonSelectDataModal.vue';
import DictSelect from '#/components/dict/DictSelect.vue';
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
import {
  canAiResourceDelete,
  canAiResourceOffline,
  canAiResourcePublish,
  canAiResourceRepublish,
  isAiResourceApprovalPending,
  isAiResourceExternallyVisible,
  resolveAiResourceDisplayStatus,
} from '#/views/ai/shared/publish-status';

interface SelectedMcpTool {
  name: string;
  description: string;
}

interface ApiKeyOption {
  id: string;
  apiKey: string;
  expiredAt?: string;
  label: string;
}

type RetrievalMode = 'HYBRID' | 'KEYWORD' | 'VECTOR';

interface BotKnowledgeBindingItem {
  knowledgeId: string;
  retrievalMode: RetrievalMode;
}

const props = defineProps<{
  bot?: BotInfo;
  hasSavePermission?: boolean;
}>();
const botStore = useBotStore();
const route = useRoute();
const botId = ref<string>((route.params.id as string) || '');
const fallbackAvatarUrl = `${import.meta.env.BASE_URL || '/'}favicon.svg`;
const options = ref<AiLlm[]>([]);
const selectedId = ref<string>('');
const llmConfig = ref({
  maxMessageCount: 0,
  maxReplyLength: 0,
  temperature: 0,
  topK: 0,
  topP: 0,
});
const dialogueSettings = ref({
  welcomeMessage: '',
  enableDeepThinking: false,
  anonymousEnabled: false,
});
const selectedPublishApiKey = ref('');
const publishApiKeyOptions = ref<ApiKeyOption[]>([]);
const publishBaseUrl = ref('');
const routerHistoryMode = import.meta.env.VITE_ROUTER_HISTORY;
const normalizePublishBaseUrl = (value: string) => {
  const raw = value.trim();
  if (!raw) {
    return '';
  }
  if (/^https?:\/\//i.test(raw)) {
    return raw.replace(/\/+$/, '');
  }
  if (raw.startsWith('//')) {
    return `${window.location.protocol}${raw}`.replace(/\/+$/, '');
  }
  // 支持仅填写 localhost 这类主机名，自动补协议和当前端口，避免被当作相对路径。
  const firstSegment = raw.split('/')[0] || '';
  const hasPort = /:\d+$/.test(firstSegment);
  let hostAndPath = raw;
  if (
    !hasPort &&
    firstSegment === window.location.hostname &&
    window.location.port
  ) {
    hostAndPath = `${firstSegment}:${window.location.port}${raw.slice(firstSegment.length)}`;
  }
  return `${window.location.protocol}//${hostAndPath}`.replace(/\/+$/, '');
};
const hasPublishBaseUrl = computed(
  () => publishBaseUrl.value.trim().length > 0,
);
const publicChatPath = computed(() =>
  routerHistoryMode === 'hash'
    ? `/#/embed/chat/${botId.value}`
    : `/embed/chat/${botId.value}`,
);
const buildPublicChatUrl = (embed = false) => {
  if (!hasPublishBaseUrl.value) {
    return '';
  }
  const base = normalizePublishBaseUrl(publishBaseUrl.value);
  const query = new URLSearchParams();
  if (selectedPublishApiKey.value) {
    query.set('token', selectedPublishApiKey.value);
  }
  if (embed) {
    query.set('embed', '1');
  }
  const queryString = query.toString();
  if (!queryString) {
    return `${base}${publicChatPath.value}`;
  }
  return `${base}${publicChatPath.value}?${queryString}`;
};
const publicChatUrl = computed(() => {
  return buildPublicChatUrl(false);
});
const publicChatEmbedUrl = computed(() => {
  return buildPublicChatUrl(true);
});
const botDisplayPublishStatus = computed(() =>
  resolveAiResourceDisplayStatus(
    botInfo.value?.displayPublishStatus,
    botInfo.value?.publishStatus,
  ),
);
const botApprovalPending = computed(() =>
  isAiResourceApprovalPending(
    botInfo.value?.displayPublishStatus,
    botInfo.value?.publishStatus,
  ),
);
const publishStatusMeta = computed<{
  description: string;
  label: string;
  type: 'danger' | 'info' | 'success' | 'warning';
}>(() => {
  switch (botDisplayPublishStatus.value) {
    case 'PUBLISHED':
      return {
        label: $t('bot.publishStatusPublished'),
        type: 'success',
        description: $t('bot.publishStatusPublishedDesc'),
      };
    case 'OFFLINE_PENDING':
      return {
        label: $t('bot.publishStatusOfflinePending'),
        type: 'warning',
        description: $t('bot.publishStatusOfflinePendingDesc'),
      };
    case 'OFFLINE':
      return {
        label: $t('bot.publishStatusOffline'),
        type: 'info',
        description: $t('bot.publishStatusOfflineDesc'),
      };
    case 'PUBLISH_PENDING':
      return {
        label: $t('bot.publishStatusPublishPending'),
        type: 'warning',
        description: $t('bot.publishStatusPublishPendingDesc'),
      };
    case 'DELETE_PENDING':
      return {
        label: $t('bot.publishStatusDeletePending'),
        type: 'danger',
        description: $t('bot.publishStatusDeletePendingDesc'),
      };
    default:
      return {
        label: $t('bot.publishStatusDraft'),
        type: 'info',
        description: $t('bot.publishStatusDraftDesc'),
      };
  }
});
const canUsePublicAccess = computed(() =>
  isAiResourceExternallyVisible(botInfo.value?.publishStatus),
);
const publishPrimaryActionLabel = computed(() =>
  canAiResourceRepublish(
    botInfo.value?.displayPublishStatus,
    botInfo.value?.publishStatus,
  )
    ? $t('button.republish')
    : $t('button.publish'),
);
const canShowPublishPrimaryAction = computed(() =>
  canAiResourcePublish(
    botInfo.value?.displayPublishStatus,
    botInfo.value?.publishStatus,
  ) ||
  canAiResourceRepublish(
    botInfo.value?.displayPublishStatus,
    botInfo.value?.publishStatus,
  ),
);
const secondaryActionLabel = computed(() => {
  if (
    canAiResourceOffline(
      botInfo.value?.displayPublishStatus,
      botInfo.value?.publishStatus,
    )
  ) {
    return $t('button.offline');
  }
  if (
    canAiResourceDelete(
      botInfo.value?.displayPublishStatus,
      botInfo.value?.publishStatus,
    )
  ) {
    return $t('button.delete');
  }
  return '';
});
const canShowSecondaryAction = computed(() =>
  Boolean(secondaryActionLabel.value),
);
const iframeCode = computed(() => {
  if (!publicChatEmbedUrl.value) {
    return '';
  }
  return `<iframe
  src="${publicChatEmbedUrl.value}"
  width="100%"
  height="720"
  style="border:0;border-radius:12px;overflow:hidden"
  loading="lazy"
  referrerpolicy="no-referrer-when-downgrade"
></iframe>`;
});
const escapeHtml = (value: string) =>
  value
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#39;');
const iframeCodeHighlighted = computed(() => {
  if (!iframeCode.value) {
    return '';
  }
  const escaped = escapeHtml(iframeCode.value);
  return escaped
    .replaceAll(
      /(&lt;\/?)([a-zA-Z][\w-]*)/g,
      '$1<span class="hljs-name">$2</span>',
    )
    .replaceAll(
      /([:@a-zA-Z_][\w:-]*)=(&quot;.*?&quot;)/g,
      '<span class="hljs-attr">$1</span>=<span class="hljs-string">$2</span>',
    );
});
watch(
  props,
  (newValue) => {
    if (!newValue.hasSavePermission) {
      selectedId.value = $t('bot.noPermission');
    } else if (newValue.bot?.modelId) {
      selectedId.value = newValue.bot.modelId;
    }

    if (newValue.bot) {
      llmConfig.value = newValue.bot.modelOptions;
    }
  },
  { immediate: true },
);
const pluginToolIdsData = ref<any>([]);
const knowledgeIdsData = ref<any>([]);
const workflowIdsData = ref<any>([]);
const mcpToolData = ref<any>([]);

const workflowData = ref<any[]>([]);
const knowledgeData = ref<any[]>([]);
const pluginToolData = ref<any[]>([]);
const retrievalModeOptions = computed(() => [
  { label: $t('bot.retrievalModes.hybrid'), value: 'HYBRID' },
  { label: $t('bot.retrievalModes.vector'), value: 'VECTOR' },
  { label: $t('bot.retrievalModes.keyword'), value: 'KEYWORD' },
]);
const normalizeRetrievalMode = (value?: string): RetrievalMode => {
  if (value === 'VECTOR' || value === 'KEYWORD' || value === 'HYBRID') {
    return value;
  }
  return 'HYBRID';
};
const buildKnowledgeBindingsPayload = (
  selectedIds: Array<number | string>,
): BotKnowledgeBindingItem[] => {
  return [...new Set((selectedIds || []).map(String).filter(Boolean))].map(
    (knowledgeId) => {
      const existing = knowledgeData.value.find(
        (item) => String(item.id) === knowledgeId,
      );
      return {
        knowledgeId,
        retrievalMode: normalizeRetrievalMode(existing?.retrievalMode),
      };
    },
  );
};
const getAiBotPluginToolList = async () => {
  api
    .post('/api/v1/pluginItem/tool/list', { botId: botId.value })
    .then((res) => {
      pluginToolData.value = res.data;
      pluginToolIdsData.value = res.data.map((item: any) => item.id);
    });
};
const getAiBotMcpToolList = async () => {
  api.get(`/api/v1/botMcp/list?botId=${botId.value}`).then((res) => {
    mcpToolData.value = res.data;
  });
};
const getAiBotKnowledgeList = async () => {
  api
    .get('/api/v1/botKnowledge/list', {
      params: {
        botId: botId.value,
      },
    })
    .then((res) => {
      knowledgeData.value = res.data.map((item: any) => {
        return {
          recordId: item.id,
          retrievalMode: normalizeRetrievalMode(item.options?.retrievalMode),
          ...item.knowledge,
        };
      });
      knowledgeIdsData.value = res.data.map(
        (item: any) => item.documentCollectionId,
      );
    });
};

const getAiBotWorkflowList = async () => {
  api
    .get('/api/v1/botWorkflow/list', {
      params: {
        botId: botId.value,
      },
    })
    .then((res) => {
      workflowData.value = res.data.map((item: any) => {
        return {
          recordId: item.id,
          ...item.workflow,
        };
      });
      workflowIdsData.value = res.data.map((item: any) => item.workflowId);
    });
};
const botInfo = ref<BotInfo>();
const basicInfoForm = ref({
  title: '',
  alias: '',
  categoryId: '',
});
const updatingBotIcon = ref(false);
const updatingBasicInfo = ref(false);
const syncingBasicInfoForm = ref(false);
const getPublishBaseUrl = async () => {
  const [, res] = await tryit(api.get)(
    '/api/v1/sysOption/list?keys=chat_publish_base_url',
  );
  if (res?.errorCode === 0) {
    publishBaseUrl.value = (res.data?.chat_publish_base_url || '').trim();
  }
};
const getBotDetail = async () => {
  api
    .get('/api/v1/bot/detail', {
      params: {
        id: botId.value,
      },
    })
    .then((res) => {
      if (res.errorCode === 0) {
        botInfo.value = res.data;
        if (res.data.options) {
          dialogueSettings.value = {
            ...dialogueSettings.value,
            ...res.data.options,
          };
        }
        if (res.data.options?.presetQuestions) {
          botStore.setPresetQuestions(res.data?.options?.presetQuestions);
        }
        syncingBasicInfoForm.value = true;
        basicInfoForm.value = {
          title: res.data.title || '',
          alias: res.data.alias || '',
          categoryId: res.data.categoryId || '',
        };
        syncingBasicInfoForm.value = false;
      }
    });
};
const formatApiKeyOptionLabel = (apiKey: string, expiredAt?: string) => {
  const normalized = String(apiKey || '').trim();
  if (!normalized) {
    return '';
  }
  const prefix = normalized.slice(0, 8);
  const suffix = normalized.slice(-6);
  const baseLabel =
    normalized.length > 18 ? `${prefix}...${suffix}` : normalized;
  return expiredAt ? `${baseLabel} · ${expiredAt}` : baseLabel;
};
const getPublishApiKeyOptions = async () => {
  const [resourceErr, resourceRes] = await tryit(api.get)(
    '/api/v1/sysApiKeyResourcePermission/list',
  );
  if (
    resourceErr ||
    resourceRes?.errorCode !== 0 ||
    !Array.isArray(resourceRes?.data)
  ) {
    publishApiKeyOptions.value = [];
    return;
  }
  const publicChatResource = resourceRes.data.find(
    (item: any) => item?.requestInterface === '/public-api/bot/chat',
  );
  if (!publicChatResource?.id) {
    publishApiKeyOptions.value = [];
    return;
  }

  const [apiKeyErr, apiKeyRes] = await tryit(api.get)(
    '/api/v1/sysApiKey/page',
    {
      params: {
        pageNumber: 1,
        pageSize: 200,
        sortKey: 'created',
        sortType: 'desc',
        status: 1,
      },
    },
  );
  if (apiKeyErr || apiKeyRes?.errorCode !== 0) {
    publishApiKeyOptions.value = [];
    return;
  }

  const records = apiKeyRes?.data?.records || [];
  const now = Date.now();
  publishApiKeyOptions.value = records
    .filter((item: any) => {
      if (item?.status !== 1) {
        return false;
      }
      if (item?.expiredAt && new Date(item.expiredAt).getTime() <= now) {
        return false;
      }
      const permissionIds = Array.isArray(item?.permissionIds)
        ? item.permissionIds.map(String)
        : [];
      return permissionIds.includes(String(publicChatResource.id));
    })
    .map((item: any) => ({
      id: String(item.id || ''),
      apiKey: String(item.apiKey || ''),
      expiredAt: item.expiredAt,
      label: formatApiKeyOptionLabel(item.apiKey, item.expiredAt),
    }));
  if (
    selectedPublishApiKey.value &&
    !publishApiKeyOptions.value.some(
      (item) => item.apiKey === selectedPublishApiKey.value,
    )
  ) {
    selectedPublishApiKey.value = '';
  }
};
const getLlmListData = async () => {
  const url = `/api/v1/model/list?modelType=chatModel&added=true`;
  api.get(url, {}).then((res) => {
    if (res.errorCode === 0) {
      options.value = res.data;
    }
  });
};
onMounted(async () => {
  getPublishBaseUrl();
  getPublishApiKeyOptions();
  getAiBotPluginToolList();
  getAiBotKnowledgeList();
  getAiBotWorkflowList();
  getAiBotMcpToolList();
  getBotDetail();
  getLlmListData();
});

const handleAnonymousAccessChange = (value: boolean | number | string) => {
  handleDialogOptionsStrChange('anonymousEnabled', value);
};

const copyText = async (value: string) => {
  // 优先使用现代剪贴板 API；在非安全上下文或权限受限场景自动走降级逻辑。
  try {
    if (navigator.clipboard?.writeText) {
      await navigator.clipboard.writeText(value);
      return;
    }
  } catch {
    // ignore and fallback
  }

  const textarea = document.createElement('textarea');
  textarea.value = value;
  textarea.setAttribute('readonly', '');
  textarea.style.position = 'fixed';
  textarea.style.left = '-9999px';
  textarea.style.top = '0';
  textarea.style.opacity = '0';
  textarea.style.pointerEvents = 'none';

  document.body.append(textarea);

  const selection = document.getSelection();
  const previousRange =
    selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;

  textarea.focus();
  textarea.select();
  textarea.setSelectionRange(0, textarea.value.length);
  const copied = document.execCommand('copy');

  textarea.remove();
  if (selection) {
    selection.removeAllRanges();
    if (previousRange) {
      selection.addRange(previousRange);
    }
  }

  if (!copied) {
    throw new Error('copy_failed');
  }
};

const handleCopyValue = async (value: string, successMessage?: string) => {
  if (!value) {
    ElMessage.warning($t('bot.chatPublishBaseUrlMissing'));
    return;
  }
  try {
    await copyText(value);
    ElMessage.success(successMessage || $t('bot.publicChatCopySuccess'));
  } catch {
    ElMessage.error($t('bot.publicChatCopyFail'));
  }
};

const openPublicPage = () => {
  if (!canUsePublicAccess.value) {
    ElMessage.warning($t('bot.publishRequiredHint'));
    return;
  }
  if (!publicChatUrl.value) {
    ElMessage.warning($t('bot.chatPublishBaseUrlMissing'));
    return;
  }
  window.open(publicChatUrl.value, '_blank', 'noopener,noreferrer');
};

const handleLlmChange = async (value: string) => {
  if (!props.bot) return;

  const [, res] = await tryit(updateLlmId)({
    id: props.bot?.id || '',
    modelId: value,
  });

  if (res?.errorCode === 0) {
    ElMessage.success($t('message.saveOkMessage'));
  } else {
    ElMessage.error(res?.message || $t('message.saveFailMessage'));
  }
};
const handleLlmOptionsChange = useDebounceFn(
  (key: keyof typeof llmConfig.value, value: number) => {
    updateLlmOptions({
      id: props.bot?.id || '',
      llmOptions: {
        [key]: value,
      },
    });
  },
  300,
);

const handleDialogOptionsStrChange = useDebounceFn(
  (
    key: keyof typeof dialogueSettings.value,
    value: boolean | number | string,
  ) => {
    updateBotOptions({
      id: props.bot?.id || '',
      options: {
        [key]: value,
      },
    });
  },
  300,
);
const pluginToolDataRef = ref();
const knowledgeDataRef = ref();
const workflowDataRef = ref();
const publishWxRef = ref();
const mcpToolDataRef = ref();

const handleAddPlugin = () => {
  pluginToolDataRef.value.openDialog(pluginToolIdsData.value);
};
const handleAddMcpTool = () => {
  const formattedSelectedMcp = formatSelectedMcpData();
  mcpToolDataRef.value.openMcpDialog(formattedSelectedMcp);
};
const handleAddKnowledge = () => {
  knowledgeDataRef.value.openDialog(knowledgeIdsData.value);
};
const handleAddWorkflow = () => {
  workflowDataRef.value.openDialog(workflowIdsData.value);
};
const confirmUpdateAiBotPlugin = (data: any) => {
  api
    .post('/api/v1/botPlugins/updateBotPluginToolIds', {
      botId: botId.value,
      pluginToolIds: data,
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.updateOkMessage'));
        getAiBotPluginToolList();
      } else {
        ElMessage.error(res.message);
      }
    });
};

const confirmUpdateAiBotKnowledge = (data: any) => {
  api
    .post('/api/v1/botKnowledge/updateBotKnowledgeIds', {
      botId: botId.value,
      knowledgeBindings: buildKnowledgeBindingsPayload(data),
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.updateOkMessage'));
        getAiBotKnowledgeList();
      } else {
        ElMessage.error(res.message);
      }
    });
};

const updateKnowledgeBindings = (bindings: BotKnowledgeBindingItem[]) => {
  return api.post('/api/v1/botKnowledge/updateBotKnowledgeIds', {
    botId: botId.value,
    knowledgeBindings: bindings,
  });
};

const handleKnowledgeRetrievalModeChange = async (
  item: any,
  value: RetrievalMode | string,
) => {
  item.retrievalMode = normalizeRetrievalMode(value);
  const bindings = knowledgeData.value.map((knowledgeItem: any) => ({
    knowledgeId: String(knowledgeItem.id),
    retrievalMode: normalizeRetrievalMode(knowledgeItem.retrievalMode),
  }));
  const res = await updateKnowledgeBindings(bindings);
  if (res.errorCode === 0) {
    ElMessage.success($t('message.updateOkMessage'));
    getAiBotKnowledgeList();
    return;
  }
  ElMessage.error(res.message || $t('message.updateFailMessage'));
};

const confirmUpdateAiBotWorkflow = (data: any) => {
  api
    .post('/api/v1/botWorkflow/updateBotWorkflowIds', {
      botId: botId.value,
      workflowIds: data,
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.updateOkMessage'));
        getAiBotWorkflowList();
      } else {
        ElMessage.error(res.message);
      }
    });
};
const confirmUpdateAiBotMcp = (data: any) => {
  api
    .post('/api/v1/botMcp/updateBotMcpToolIds', {
      botId: botId.value,
      mcpSelectedData: data,
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.updateOkMessage'));
        getAiBotMcpToolList();
      } else {
        ElMessage.error(res.message);
      }
    });
};
const deletePluginTool = (item: any) => {
  api
    .post('/api/v1/botPlugins/doRemove', {
      botId: botId.value,
      pluginToolId: item.id,
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.deleteOkMessage'));
        getAiBotPluginToolList();
      } else {
        ElMessage.error(res.message);
      }
    });
};

const deleteBotMcpTool = (item: any) => {
  api
    .post('/api/v1/botMcp/remove', {
      id: item.id,
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.deleteOkMessage'));
        getAiBotMcpToolList();
      } else {
        ElMessage.error(res.message);
      }
    });
};

const deleteKnowledge = async (item: any) => {
  try {
    await ElMessageBox.confirm(
      $t('message.deleteAlert'),
      $t('message.noticeTitle'),
      {
        confirmButtonText: $t('button.confirm'),
        cancelButtonText: $t('button.cancel'),
        type: 'warning',
      },
    );
  } catch {
    return;
  }
  api
    .post('/api/v1/botKnowledge/remove', {
      id: item.recordId,
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.deleteOkMessage'));
        getAiBotKnowledgeList();
      } else {
        ElMessage.error(res.message);
      }
    });
};

const deleteWorkflow = (item: any) => {
  api
    .post('/api/v1/botWorkflow/remove', {
      id: item.recordId,
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.deleteOkMessage'));
        getAiBotWorkflowList();
      } else {
        ElMessage.error(res.message);
      }
    });
};

const problemPresuppositionRef = ref();

const handleAddPresetQuestion = () => {
  problemPresuppositionRef.value.openDialog(
    botInfo.value?.options?.presetQuestions,
  );
};

const handleProblemPresuppositionSuccess = (data: any) => {
  api
    .post('/api/v1/bot/updateOptions', {
      id: botId.value,
      options: {
        presetQuestions: data,
      },
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.updateOkMessage'));
        getBotDetail();
        botStore.setPresetQuestions(data);
      } else {
        ElMessage.error(res.message);
      }
    });
};
const handleDeletePresetQuestion = (item: any) => {
  const tempData = botInfo.value?.options?.presetQuestions?.filter(
    (i: any) => i.key !== item,
  );
  api
    .post('/api/v1/bot/updateOptions', {
      id: botId.value,
      options: {
        presetQuestions: tempData,
      },
    })
    .then((res) => {
      if (res.errorCode === 0) {
        getBotDetail();
      }
    });
};
const handlePublishWx = () => {
  publishWxRef.value.openDialog(botId.value, botInfo.value?.options || {});
};
const handleLifecycleAction = async () => {
  if (!botInfo.value) {
    return;
  }
  if (
    botApprovalPending.value
  ) {
    ElMessage.warning($t('bot.publishPendingHint'));
    return;
  }
  try {
    await ElMessageBox.confirm(
      canAiResourceRepublish(
        botInfo.value.displayPublishStatus,
        botInfo.value.publishStatus,
      )
        ? $t('bot.submitRepublishApprovalConfirm')
        : $t('bot.submitPublishApprovalConfirm'),
      $t('message.noticeTitle'),
      {
        confirmButtonText: $t('button.confirm'),
        cancelButtonText: $t('button.cancel'),
        type: 'info',
      },
    );
  } catch {
    return;
  }
  const res = await submitBotPublishApproval(String(botInfo.value.id));
  if (res.errorCode === 0) {
    ElMessage.success(res.message || $t('message.saveOkMessage'));
    getBotDetail();
  } else {
    ElMessage.error(res.message || $t('message.saveFailMessage'));
  }
};
const handleSecondaryAction = async () => {
  if (!botInfo.value) {
    return;
  }
  if (
    botApprovalPending.value
  ) {
    ElMessage.warning($t('bot.publishPendingHint'));
    return;
  }
  const canOffline = canAiResourceOffline(
    botInfo.value.displayPublishStatus,
    botInfo.value.publishStatus,
  );
  const canDelete = canAiResourceDelete(
    botInfo.value.displayPublishStatus,
    botInfo.value.publishStatus,
  );
  if (!canOffline && !canDelete) {
    return;
  }
  try {
    await ElMessageBox.confirm(
      canOffline
        ? $t('bot.submitOfflineApprovalConfirm')
        : $t('bot.submitDeleteApprovalConfirm'),
      $t('message.noticeTitle'),
      {
        confirmButtonText: $t('button.confirm'),
        cancelButtonText: $t('button.cancel'),
        type: 'warning',
      },
    );
  } catch {
    return;
  }
  const res = canOffline
    ? await submitBotOfflineApproval(String(botInfo.value.id))
    : await submitBotDeleteApproval(String(botInfo.value.id));
  if (res.errorCode === 0) {
    ElMessage.success(res.message || $t('message.saveOkMessage'));
    getBotDetail();
  } else {
    ElMessage.error(res.message || $t('message.saveFailMessage'));
  }
};
const handleUpdatePublishWx = () => {
  api
    .post('/api/v1/bot/updateOptions', {
      id: botId.value,
      options: {
        weChatMpAppId: '',
        weChatMpSecret: '',
        weChatMpToken: '',
        EncodingAESKey: '',
      },
    })
    .then((res) => {
      if (res.errorCode === 0) {
        ElMessage.success($t('message.updateOkMessage'));
        getBotDetail();
      } else {
        ElMessage.error(res.message);
      }
    });
};
const formatSelectedMcpData = () => {
  // 定义格式化后的结果，与组件内selectedToolMap结构一致
  const formattedData: Record<number | string, SelectedMcpTool[]> = {};

  // 遍历已有的MCP工具列表（mcpToolData.value）
  mcpToolData.value.forEach((mcpItem: any) => {
    const mcpParentId = mcpItem.mcpId || mcpItem.id;

    const toolInfo: SelectedMcpTool = {
      name: mcpItem.mcpToolName,
      description: mcpItem.mcpToolDescription,
    };

    if (!formattedData[mcpParentId]) {
      formattedData[mcpParentId] = [];
    }
    formattedData[mcpParentId].push(toolInfo);
  });

  return formattedData;
};

const persistBotBasicInfo = async (
  patch: Partial<Pick<BotInfo, 'alias' | 'categoryId' | 'icon' | 'title'>>,
) => {
  if (!botInfo.value || !props.hasSavePermission) {
    return false;
  }
  const snapshot = { ...botInfo.value };
  const next = {
    ...snapshot,
    ...patch,
  };

  botInfo.value = next;
  const [, res] = await tryit(updateBotApi)({
    id: String(next.id),
    icon: next.icon || '',
    title: next.title || '',
    alias: next.alias || '',
    description: next.description || '',
    categoryId: next.categoryId,
    status: next.status,
  });

  if (res?.errorCode === 0) {
    return true;
  }

  botInfo.value = snapshot;
  ElMessage.error(res?.message || $t('message.saveFailMessage'));
  return false;
};

const handleBotIconUpdate = async (iconPath: string) => {
  if (!iconPath || !botInfo.value) {
    return;
  }
  if (!props.hasSavePermission) {
    ElMessage.warning($t('bot.noPermission'));
    return;
  }
  if (updatingBotIcon.value) {
    return;
  }
  updatingBotIcon.value = true;
  const ok = await persistBotBasicInfo({ icon: iconPath });
  updatingBotIcon.value = false;
  if (ok) {
    ElMessage.success($t('message.updateOkMessage'));
  }
};

const handleBasicInfoChange = async (
  key: 'alias' | 'categoryId' | 'title',
  value: any,
) => {
  if (
    !botInfo.value ||
    !props.hasSavePermission ||
    syncingBasicInfoForm.value
  ) {
    return;
  }
  if (updatingBasicInfo.value) {
    return;
  }

  const normalizedValue =
    key === 'categoryId' ? value : String(value || '').trim();
  if ((key === 'title' || key === 'alias') && !normalizedValue) {
    ElMessage.warning($t('message.required'));
    basicInfoForm.value[key] = botInfo.value[key] as string;
    return;
  }

  if (botInfo.value[key] === normalizedValue) {
    basicInfoForm.value[key] = normalizedValue as any;
    return;
  }

  updatingBasicInfo.value = true;
  const ok = await persistBotBasicInfo({
    [key]: normalizedValue,
  } as Partial<Pick<BotInfo, 'alias' | 'categoryId' | 'title'>>);
  updatingBasicInfo.value = false;

  if (ok) {
    ElMessage.success($t('message.updateOkMessage'));
    basicInfoForm.value[key] = normalizedValue as any;
  } else {
    basicInfoForm.value[key] = botInfo.value[key] as any;
  }
};
</script>

<template>
  <div class="config-container flex flex-col gap-3">
    <!-- 基础信息 -->
    <div
      class="bg-background dark:border-border flex flex-col gap-3 rounded-lg p-3 dark:border"
    >
      <h1 class="text-base font-medium">{{ $t('bot.basicInfo') }}</h1>
      <div class="bot-basic-info-container">
        <div class="bot-basic-info-layout">
          <div class="bot-avatar-panel">
            <span class="bot-avatar-label">{{ $t('common.avatar') }}</span>
            <div
              class="bot-avatar-upload-wrap"
              :class="
                !hasSavePermission || updatingBotIcon ? 'is-disabled' : ''
              "
            >
              <UploadAvatar
                v-if="botInfo"
                v-model="botInfo.icon"
                @success="handleBotIconUpdate"
              />
              <ElSkeleton v-else animated :rows="1" style="width: 100px" />
            </div>
          </div>
          <div class="bot-basic-form-panel">
            <div class="bot-basic-form-item">
              <span class="bot-basic-form-label">{{
                $t('aiWorkflow.title')
              }}</span>
              <ElInput
                v-model="basicInfoForm.title"
                :disabled="!hasSavePermission || updatingBasicInfo"
                @change="(value) => handleBasicInfoChange('title', value)"
              />
            </div>
            <div class="bot-basic-form-item">
              <span class="bot-basic-form-label">{{ $t('plugin.alias') }}</span>
              <ElInput
                v-model="basicInfoForm.alias"
                :disabled="!hasSavePermission || updatingBasicInfo"
                @change="(value) => handleBasicInfoChange('alias', value)"
              />
            </div>
            <div class="bot-basic-form-item">
              <span class="bot-basic-form-label">{{
                $t('aiWorkflow.categoryId')
              }}</span>
              <DictSelect
                v-model="basicInfoForm.categoryId"
                dict-code="aiBotCategory"
                :disabled="!hasSavePermission || updatingBasicInfo"
                @change="
                  (value: any) => handleBasicInfoChange('categoryId', value)
                "
              />
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 大模型 -->
    <div
      class="bg-background dark:border-border flex flex-col gap-3 rounded-lg p-3 dark:border"
    >
      <h1 class="text-base font-medium">{{ $t('bot.llm') }}</h1>
      <div
        class="llm-back-container dark:border-border flex w-full flex-col justify-between gap-1 rounded-lg p-3 dark:border"
      >
        <ElSelect
          v-model="selectedId"
          :options="options"
          :props="{ value: 'id', label: 'title' }"
          :disabled="!hasSavePermission"
          @change="handleLlmChange"
        />
        <!-- 温度 -->
        <ElRow :gutter="12" align="middle" type="flex">
          <ElCol class="options-config-item-left">
            <span class="config-font-style">{{ $t('bot.temperature') }}</span>
          </ElCol>
          <ElCol class="options-config-item-middle">
            <ElSlider
              :min="0.1"
              :max="1"
              :step="0.1"
              :disabled="!hasSavePermission"
              v-model="llmConfig.temperature"
              @change="
                (value) =>
                  handleLlmOptionsChange('temperature', value as number)
              "
            />
          </ElCol>
          <ElCol class="options-config-item-right">
            <ElInputNumber
              :min="0.1"
              :max="1"
              :step="0.1"
              :disabled="!hasSavePermission"
              v-model="llmConfig.temperature"
              @change="
                (value) =>
                  handleLlmOptionsChange('temperature', value as number)
              "
            />
          </ElCol>
        </ElRow>
        <ElRow :gutter="12" align="middle" type="flex">
          <ElCol class="options-config-item-left">
            <span class="config-font-style">TopK</span>
          </ElCol>
          <ElCol class="options-config-item-middle">
            <ElSlider
              :min="1"
              :max="10"
              :step="1"
              :disabled="!hasSavePermission"
              v-model="llmConfig.topK"
              @change="
                (value) => handleLlmOptionsChange('topK', value as number)
              "
            />
          </ElCol>
          <ElCol class="options-config-item-right">
            <ElInputNumber
              :min="1"
              :max="10"
              :step="1"
              :disabled="!hasSavePermission"
              v-model="llmConfig.topK"
              @change="
                (value) => handleLlmOptionsChange('topK', value as number)
              "
            />
          </ElCol>
        </ElRow>
        <ElRow :gutter="12" align="middle" type="flex">
          <ElCol class="options-config-item-left">
            <span class="config-font-style">TopP</span>
          </ElCol>
          <ElCol class="options-config-item-middle">
            <ElSlider
              :min="0.1"
              :max="1"
              :step="0.1"
              :disabled="!hasSavePermission"
              v-model="llmConfig.topP"
              @change="
                (value) => handleLlmOptionsChange('topP', value as number)
              "
            />
          </ElCol>
          <ElCol class="options-config-item-right">
            <ElInputNumber
              :min="0.1"
              :max="1"
              :step="0.1"
              :disabled="!hasSavePermission"
              v-model="llmConfig.topP"
              @change="
                (value) => handleLlmOptionsChange('topP', value as number)
              "
            />
          </ElCol>
        </ElRow>
        <ElRow :gutter="12" align="middle" type="flex">
          <ElCol class="options-config-item-left">
            <span class="config-font-style">{{
              $t('bot.maxReplyLength')
            }}</span>
          </ElCol>
          <ElCol class="options-config-item-middle">
            <ElSlider
              :min="1024"
              :max="20000"
              :step="1000"
              :disabled="!hasSavePermission"
              v-model="llmConfig.maxReplyLength"
              @change="
                (value) =>
                  handleLlmOptionsChange('maxReplyLength', value as number)
              "
            />
          </ElCol>
          <ElCol class="options-config-item-right">
            <ElInputNumber
              :min="1024"
              :max="20000"
              :step="1000"
              :disabled="!hasSavePermission"
              v-model="llmConfig.maxReplyLength"
              @change="
                (value) =>
                  handleLlmOptionsChange('maxReplyLength', value as number)
              "
            />
          </ElCol>
        </ElRow>
        <ElRow :gutter="12" align="middle" type="flex">
          <ElCol class="options-config-item-left">
            <span class="config-font-style">{{ $t('bot.historyCount') }}</span>
          </ElCol>
          <ElCol class="options-config-item-middle">
            <ElSlider
              :min="1"
              :max="100"
              :step="10"
              :disabled="!hasSavePermission"
              v-model="llmConfig.maxMessageCount"
              @change="
                (value) =>
                  handleLlmOptionsChange('maxMessageCount', value as number)
              "
            />
          </ElCol>
          <ElCol class="options-config-item-right">
            <ElInputNumber
              :min="1"
              :max="100"
              :step="1"
              :disabled="!hasSavePermission"
              v-model="llmConfig.maxMessageCount"
              @change="
                (value) =>
                  handleLlmOptionsChange('maxMessageCount', value as number)
              "
            />
          </ElCol>
        </ElRow>
      </div>
    </div>

    <!-- 技能 -->
    <div
      class="bg-background dark:border-border flex flex-col gap-3 rounded-lg p-3 dark:border"
    >
      <h1 class="text-base font-medium">
        {{ $t('bot.skill') }}
      </h1>
      <div class="flex w-full flex-col justify-between">
        <ElCollapse expand-icon-position="left">
          <ElCollapseItem>
            <template #title>
              <div class="flex items-center justify-between pr-2">
                <span>{{ $t('menus.ai.workflow') }}</span>
                <div class="collapse-right-container">
                  <span class="badge-circle">
                    {{ workflowData.length }}
                  </span>
                  <span @click="handleAddWorkflow()">
                    <ElIcon>
                      <Plus />
                    </ElIcon>
                  </span>
                </div>
              </div>
            </template>
            <CollapseViewItem :data="workflowData" @delete="deleteWorkflow" />
          </ElCollapseItem>
          <ElCollapseItem>
            <template #title>
              <div class="flex items-center justify-between pr-2">
                <span>{{ $t('menus.ai.documentCollection') }}</span>
                <div class="collapse-right-container">
                  <span class="badge-circle">
                    {{ knowledgeData.length }}
                  </span>
                  <span @click="handleAddKnowledge()">
                    <ElIcon>
                      <Plus />
                    </ElIcon>
                  </span>
                </div>
              </div>
            </template>
            <div class="knowledge-binding-list">
              <div
                v-for="item in knowledgeData"
                :key="item.recordId"
                class="knowledge-binding-item"
              >
                <div class="knowledge-binding-main">
                  <ElAvatar
                    :src="item.icon || fallbackAvatarUrl"
                    shape="circle"
                  />
                  <div class="knowledge-binding-content">
                    <div class="knowledge-binding-title">
                      {{ item.title }}
                    </div>
                    <div class="knowledge-binding-description">
                      {{ item.description }}
                    </div>
                  </div>
                </div>
                <div class="knowledge-binding-actions" @click.stop>
                  <ElSelect
                    :model-value="item.retrievalMode"
                    class="knowledge-binding-select"
                    size="small"
                    @change="
                      (value) => handleKnowledgeRetrievalModeChange(item, value)
                    "
                  >
                    <ElOption
                      v-for="option in retrievalModeOptions"
                      :key="option.value"
                      :label="option.label"
                      :value="option.value"
                    />
                  </ElSelect>
                  <ElIcon
                    class="knowledge-binding-delete"
                    color="var(--el-color-danger)"
                    size="20px"
                    @click="deleteKnowledge(item)"
                  >
                    <Delete />
                  </ElIcon>
                </div>
              </div>
            </div>
          </ElCollapseItem>
          <ElCollapseItem>
            <template #title>
              <div class="flex items-center justify-between pr-2">
                <span>{{ $t('menus.ai.plugin') }}</span>
                <div class="collapse-right-container">
                  <span class="badge-circle">
                    {{ pluginToolData.length }}
                  </span>
                  <span @click="handleAddPlugin()">
                    <ElIcon>
                      <Plus />
                    </ElIcon>
                  </span>
                </div>
              </div>
            </template>
            <CollapseViewItem
              :data="pluginToolData"
              title-key="name"
              @delete="deletePluginTool"
            />
          </ElCollapseItem>
          <ElCollapseItem title="MCP">
            <template #title>
              <div class="flex items-center justify-between pr-2">
                <span>MCP</span>
                <div class="collapse-right-container">
                  <span class="badge-circle">
                    {{ mcpToolData.length }}
                  </span>
                  <span @click="handleAddMcpTool()">
                    <ElIcon>
                      <Plus />
                    </ElIcon>
                  </span>
                </div>
              </div>
            </template>
            <CollapseViewItem
              :data="mcpToolData"
              title-key="mcpToolName"
              description-key="mcpToolDescription"
              @delete="deleteBotMcpTool"
            />
          </ElCollapseItem>
        </ElCollapse>
      </div>
    </div>

    <!-- 对话设置 -->
    <div
      class="bg-background dark:border-border flex flex-col gap-3 rounded-lg p-3 dark:border"
    >
      <h1 class="text-base font-medium">
        {{ $t('bot.conversationSettings') }}
      </h1>
      <div class="flex w-full flex-col justify-between rounded-lg">
        <ElCollapse expand-icon-position="left">
          <ElCollapseItem>
            <template #title>
              <div class="flex items-center justify-between pr-2">
                <span>{{ $t('bot.problemPresupposition') }}</span>
                <span @click="handleAddPresetQuestion()">
                  <ElIcon>
                    <Plus />
                  </ElIcon>
                </span>
              </div>
            </template>
            <div class="question-container">
              <div
                v-for="item in getPerQuestions(botStore?.presetQuestions)"
                :key="item.key"
              >
                <div class="presetQues-container" v-if="item.description">
                  <span>{{ item.description }}</span>
                  <ElIcon
                    color="var(--el-color-danger)"
                    size="20px"
                    @click="handleDeletePresetQuestion(item.key)"
                    class="el-list-item-delete-container"
                  >
                    <Delete />
                  </ElIcon>
                </div>
              </div>
            </div>
          </ElCollapseItem>
          <ElCollapseItem :title="$t('bot.welcomeMessage')">
            <div class="bg-[var(--bot-collapse-itme-back)] p-2.5">
              <ElInput
                v-model="dialogueSettings.welcomeMessage"
                :placeholder="$t('bot.placeholder.welcome')"
                type="textarea"
                @change="
                  (value) =>
                    handleDialogOptionsStrChange('welcomeMessage', value)
                "
              />
            </div>
          </ElCollapseItem>
          <ElCollapseItem :title="$t('bot.deepThinking')">
            <div class="enable-think-container">
              <div>{{ $t('bot.enableDeepThinking') }}</div>
              <ElSwitch
                v-model="dialogueSettings.enableDeepThinking"
                @change="
                  (value: string | number | boolean) =>
                    handleDialogOptionsStrChange('enableDeepThinking', value)
                "
              />
            </div>
          </ElCollapseItem>
        </ElCollapse>
      </div>
    </div>

    <!-- 发布 -->
    <div
      class="publish-container bg-background dark:border-border flex flex-col gap-3 rounded-lg p-3 dark:border"
    >
      <h1 class="text-base font-medium">
        {{ $t('bot.publish') }}
      </h1>
      <div class="publish-summary-card">
        <div class="publish-summary-main">
          <div class="publish-summary-label">
            {{ $t('bot.publishStatusLabel') }}
          </div>
          <div class="publish-summary-row">
            <ElTag :type="publishStatusMeta.type" effect="plain" round>
              {{ publishStatusMeta.label }}
            </ElTag>
            <span
              v-if="botInfo?.currentApprovalInstanceId"
              class="publish-summary-instance"
            >
              #{{ botInfo.currentApprovalInstanceId }}
            </span>
          </div>
          <p class="publish-summary-desc">
            {{ publishStatusMeta.description }}
          </p>
        </div>
        <div class="publish-summary-actions">
          <ElButton
            v-if="canShowPublishPrimaryAction"
            type="primary"
            :disabled="!hasSavePermission"
            @click="handleLifecycleAction"
          >
            {{ publishPrimaryActionLabel }}
          </ElButton>
          <ElButton
            v-if="canShowSecondaryAction"
            plain
            :type="secondaryActionLabel === $t('button.delete') ? 'danger' : 'default'"
            :disabled="!hasSavePermission"
            @click="handleSecondaryAction"
          >
            {{ secondaryActionLabel }}
          </ElButton>
        </div>
      </div>
      <div class="flex w-full flex-col justify-between rounded-lg">
        <ElCollapse expand-icon-position="left">
          <ElCollapseItem :title="$t('bot.postToWeChatOfficialAccount')">
            <div class="publish-wx-container">
              <div class="publish-wx">
                <span v-if="botInfo?.options?.weChatMpAppId">{{
                  $t('bot.configured')
                }}</span>
                <span v-else>{{ $t('bot.notConfigured') }}</span>
                <div class="publish-config-operation">
                  <div
                    class="publish-wx-right-container"
                    @click="handlePublishWx"
                  >
                    <ElButton link type="primary">
                      <ElIcon class="mr-1">
                        <Setting />
                      </ElIcon>
                      {{ $t('button.edit') }}
                    </ElButton>
                  </div>
                  <div
                    v-if="botInfo?.options?.weChatMpAppId"
                    class="publish-wx-right-container"
                    @click="handleUpdatePublishWx"
                  >
                    <ElButton link type="danger">
                      <ElIcon class="mr-1">
                        <Delete />
                      </ElIcon>
                      {{ $t('button.delete') }}
                    </ElButton>
                  </div>
                </div>
              </div>
            </div>
          </ElCollapseItem>
          <ElCollapseItem :title="$t('bot.publishExternalLink')">
            <div class="publish-external-container">
              <div class="publish-external-top">
                <span>{{ $t('bot.allowAnonymousAccess') }}</span>
                <ElSwitch
                  v-model="dialogueSettings.anonymousEnabled"
                  @change="handleAnonymousAccessChange"
                />
              </div>
              <div v-if="!hasPublishBaseUrl" class="publish-base-url-warning">
                <ElAlert
                  :title="$t('bot.chatPublishBaseUrlMissing')"
                  type="warning"
                  :closable="false"
                />
              </div>
              <div class="publish-external-item">
                <label class="publish-external-label">
                  {{ $t('bot.chatAccessToken') }}
                </label>
                <ElSelect
                  v-model="selectedPublishApiKey"
                  clearable
                  filterable
                  class="w-full"
                  :placeholder="$t('bot.chatAccessTokenPlaceholder')"
                >
                  <ElOption
                    v-for="item in publishApiKeyOptions"
                    :key="item.id"
                    :label="item.label"
                    :value="item.apiKey"
                  />
                </ElSelect>
              </div>
              <div class="publish-external-item">
                <label class="publish-external-label">
                  {{ $t('bot.chatExternalLink') }}
                </label>
                <div
                  v-if="!canUsePublicAccess"
                  class="publish-external-alert"
                >
                  <ElAlert
                    :title="$t('bot.publishRequiredHint')"
                    type="info"
                    :closable="false"
                  />
                </div>
                <ElInput :model-value="publicChatUrl" readonly />
                <div class="publish-external-actions">
                  <ElButton
                    size="small"
                    type="primary"
                    plain
                    :disabled="!canUsePublicAccess"
                    @click="handleCopyValue(publicChatUrl)"
                  >
                    <ElIcon class="mr-1">
                      <CopyDocument />
                    </ElIcon>
                    {{ $t('bot.copyLink') }}
                  </ElButton>
                  <ElButton
                    size="small"
                    type="primary"
                    :disabled="!canUsePublicAccess"
                    @click="openPublicPage"
                  >
                    <ElIcon class="mr-1">
                      <Link />
                    </ElIcon>
                    {{ $t('bot.openPublicPage') }}
                  </ElButton>
                </div>
              </div>
              <div class="publish-external-item">
                <label class="publish-external-label flex items-center gap-1">
                  <span>{{ $t('bot.iframeEmbedCode') }}</span>
                  <ElTooltip effect="dark" placement="top">
                    <template #content>
                      <div>{{ $t('bot.embedUsageTip1') }}</div>
                      <div class="mt-1">{{ $t('bot.embedUsageTip2') }}</div>
                    </template>
                    <ElIcon
                      class="cursor-pointer text-gray-400 transition-colors hover:text-gray-600"
                    >
                      <InfoFilled />
                    </ElIcon>
                  </ElTooltip>
                </label>
                <div class="publish-external-code-preview">
                  <div class="publish-external-code-topbar">HTML</div>
                  <!-- eslint-disable vue/no-v-html -->
                  <pre class="publish-external-code-block"><code
                    class="hljs language-xml"
                    v-html="iframeCodeHighlighted"
                  ></code></pre>
                  <!-- eslint-enable vue/no-v-html -->
                </div>
                <div class="publish-external-actions">
                  <ElButton
                    size="small"
                    plain
                    :disabled="!canUsePublicAccess"
                    @click="handleCopyValue(iframeCode)"
                  >
                    <ElIcon class="mr-1">
                      <CopyDocument />
                    </ElIcon>
                    {{ $t('bot.copyIframeCode') }}
                  </ElButton>
                </div>
              </div>
            </div>
          </ElCollapseItem>
        </ElCollapse>
      </div>
    </div>

    <!-- 选择插件-->
    <CommonSelectDataModal
      :title="$t('menus.ai.plugin')"
      width="730"
      ref="pluginToolDataRef"
      page-url="/api/v1/plugin/pageByCategory"
      :has-parent="true"
      @get-data="confirmUpdateAiBotPlugin"
      :extra-query-params="{
        category: 0,
      }"
    />

    <!-- 选择知识库-->
    <CommonSelectDataModal
      :title="$t('menus.ai.documentCollection')"
      width="730"
      ref="knowledgeDataRef"
      page-url="/api/v1/documentCollection/page"
      :extra-query-params="{ publishedOnly: true }"
      @get-data="confirmUpdateAiBotKnowledge"
    />

    <!-- 选择工作流-->
    <CommonSelectDataModal
      :title="$t('menus.ai.workflow')"
      width="730"
      ref="workflowDataRef"
      page-url="/api/v1/workflow/page"
      :extra-query-params="{ publishedOnly: true }"
      @get-data="confirmUpdateAiBotWorkflow"
    />

    <!-- 选择MCP-->
    <CommonSelectDataModal
      :title="$t('menus.ai.mcp')"
      width="730"
      ref="mcpToolDataRef"
      page-url="/api/v1/mcp/pageTools?status=1"
      title-key="title"
      :has-parent="true"
      :is-select-mcp="true"
      @get-data="confirmUpdateAiBotMcp"
    />

    <!--预设问题-->
    <ProblemPresupposition
      ref="problemPresuppositionRef"
      @success="handleProblemPresuppositionSuccess"
    />
    <PublishWxOfficalAccount ref="publishWxRef" @reload="getBotDetail()" />
  </div>
</template>

<style scoped>
.config-container {
  width: 100%;
  height: 100%;
  min-height: 100%;
  overflow-y: auto;
  border-radius: 8px;
}

.collapse-right-container {
  display: flex;
  flex-direction: row;
  gap: 5px;
  align-items: center;
}

.badge-circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  vertical-align: middle;
  color: var(--el-color-white);
  background-color: var(--el-color-primary);
  border-radius: 50%;
}

.presetQues-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 24px 12px 12px;
  background-color: var(--el-bg-color);
  border-radius: 8px;
}

.preset-delete {
  cursor: pointer;
}

.config-font-style {
  font-family: PingFangSC, 'PingFang SC';
  font-size: 14px;
  font-weight: 500;
  line-height: 22px;
  color: var(--el-text-color-primary);
}

.options-config-item-left {
  flex: 0 0 auto;
}

:deep(.el-collapse-item__title) {
  font-size: 14px;
  font-weight: 500;
  line-height: 22px;
  color: var(--el-text-color-primary);
}

.options-config-item-middle {
  flex: 1;
  margin: 0 12px;
}

.options-config-item-right {
  flex: 0 0 auto;
  width: auto;
}

:deep(.el-slider__runway) {
  height: 4px;
}

:deep(.el-slider__bar) {
  height: 4px;
}

:deep(.el-slider__button) {
  width: 14px;
  height: 14px;
}

.enable-think-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 12px 12px;
  background-color: var(--bot-collapse-itme-back);
}

.publish-wx-container {
  padding: 12px;
  background-color: var(--bot-collapse-itme-back);
}

.publish-summary-card {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
  background: hsl(var(--surface-subtle) / 78%);
  border: 1px solid hsl(var(--line-subtle));
  border-radius: 16px;
}

.publish-summary-main {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 8px;
  min-width: 220px;
}

.publish-summary-label {
  font-size: 13px;
  font-weight: 600;
  color: hsl(var(--muted-foreground));
}

.publish-summary-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

.publish-summary-instance {
  font-size: 12px;
  color: hsl(var(--muted-foreground));
}

.publish-summary-desc {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: hsl(var(--text-secondary));
}

.publish-summary-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

.publish-wx {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 45px;
  padding: 0 8px;
  background-color: var(--el-bg-color);
  border-radius: 8px;
}

.publish-wx-right-container {
  display: flex;
  gap: 5px;
  align-items: center;
  justify-content: flex-end;
  cursor: pointer;
}

.publish-config-operation {
  display: flex;
  gap: 5px;
  align-items: center;
  justify-content: flex-end;
}

.publish-external-container {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 12px;
  background-color: var(--bot-collapse-itme-back);
}

.publish-external-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px;
  background: var(--el-bg-color);
  border-radius: 8px;
}

.publish-base-url-warning {
  margin-bottom: 2px;
}

.publish-external-item {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  padding: 12px;
  background: var(--el-bg-color);
  border-radius: 8px;
}

.publish-external-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--el-text-color-regular);
}

.publish-external-hint {
  font-size: 12px;
  line-height: 1.5;
  color: var(--el-text-color-secondary);
}

.publish-external-actions {
  display: flex;
  justify-content: flex-end;
}

.publish-external-alert {
  margin-top: 8px;
}

.publish-external-code-preview {
  max-width: 100%;
  overflow: hidden;
  background: #0f172a;
  border: 1px solid #1e293b;
  border-radius: 10px;
}

.publish-external-code-topbar {
  padding: 8px 12px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  color: #93c5fd;
  background: #111b31;
  border-bottom: 1px solid #1f2d49;
}

.publish-external-code-block {
  width: 100%;
  max-width: 100%;
  max-height: 180px;
  padding: 10px 12px;
  margin: 0;
  overflow: auto;
}

.publish-external-code-block code {
  display: block;
  min-width: 0;
  font-family:
    ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
    'Courier New', monospace;
  font-size: 12px;
  line-height: 1.6;
  color: #d8e1f0;
  word-break: normal;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.publish-external-code-block code .hljs-tag,
.publish-external-code-block code .hljs-name,
.publish-external-code-block code .hljs-keyword {
  color: #93c5fd;
}

.publish-external-code-block code .hljs-attr {
  color: #fcd34d;
}

.publish-external-code-block code .hljs-string {
  color: #86efac;
}

:deep(.el-collapse) {
  box-sizing: border-box;
  height: 100%;
  overflow: hidden !important;
  border-radius: 8px !important;
}

:deep(.el-collapse-item__header) {
  background-color: var(--bot-collapse-itme-back);
  border-bottom: 1px solid #e4e7ed;
  border-radius: 0;
}

.dark .el-collapse :deep(.el-collapse-item__header) {
  border-bottom: 1px solid hsl(var(--border));
}

:deep(.el-collapse-item:last-child .el-collapse-item__header) {
  border-bottom: none;
}

:deep(.el-collapse-icon-position-left .el-collapse-item__header) {
  padding: 8px;
}

.llm-back-container {
  background-color: var(--bot-collapse-itme-back);
}

.publish-container {
  flex: 1;
}

.el-list-item-delete-container {
  cursor: pointer;
}

:deep(.el-collapse-item__content) {
  height: 100%;
  padding: 0;
}

.question-container {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  height: auto;
  padding: 10px;
  background-color: var(--bot-collapse-itme-back);
}

.bot-basic-info-container {
  padding: 16px 20px;
  background-color: var(--bot-collapse-itme-back);
  border-radius: 8px;
}

.bot-basic-info-layout {
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: stretch;
}

.bot-avatar-panel {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.bot-basic-form-panel {
  display: flex;
  flex-direction: column;
  gap: 20px;
  width: 100%;
}

.bot-basic-form-item {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.bot-avatar-label,
.bot-basic-form-label {
  flex: 0 0 60px;
  padding-right: 16px;
  font-size: 14px;
  font-weight: 500;
  color: var(--el-text-color-primary);
  text-align: left;
}

.bot-avatar-upload-wrap {
  flex: 1;
}

.bot-basic-form-item > *:not(.bot-basic-form-label) {
  flex: 1;
}

.bot-avatar-upload-wrap.is-disabled {
  pointer-events: none;
  opacity: 0.6;
}

.bot-avatar-upload-wrap :deep(.avatar-uploader .avatar) {
  width: 50px;
  height: 50px;
  object-fit: cover;
  border-radius: 50%;
}

.bot-avatar-upload-wrap :deep(.el-icon.avatar-uploader-icon) {
  width: 50px;
  height: 50px;
  font-size: 18px;
  border-radius: 50%;
}

.bot-avatar-upload-wrap :deep(.avatar-uploader .el-upload) {
  width: 50px;
  height: 50px;
  border-radius: 50%;
}

.knowledge-binding-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 10px;
  background-color: var(--bot-collapse-itme-back);
}

.knowledge-binding-item {
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  padding: 12px;
  background-color: hsl(var(--background));
  border-radius: 8px;
}

.knowledge-binding-main {
  display: flex;
  flex: 1;
  gap: 10px;
  align-items: center;
  min-width: 0;
}

.knowledge-binding-content {
  min-width: 0;
}

.knowledge-binding-title {
  font-size: 12px;
  font-weight: 500;
  line-height: 24px;
  color: var(--el-text-color-primary);
}

.knowledge-binding-description {
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 12px;
  line-height: 20px;
  color: var(--el-text-color-secondary);
  white-space: nowrap;
}

.knowledge-binding-actions {
  display: flex;
  gap: 12px;
  align-items: center;
}

.knowledge-binding-select {
  width: 140px;
}

.knowledge-binding-delete {
  cursor: pointer;
}
</style>
