<script setup lang="ts">
/* cspell:ignore tryit */
import type {
  AgentCapabilityKind,
  AgentOption,
  AgentValidationIssue,
} from './types';

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

import { ElMessage, ElMessageBox } from 'element-plus';
import { tryit } from 'radash';

import { api } from '#/api/request';
import {
  canAiResourceOffline,
  canAiResourcePublish,
  canAiResourceRepublish,
  isAiResourceApprovalPending,
} from '#/views/ai/shared/publish-status';

import {
  getAgentDetail,
  getAgentModels,
  getPublishedKnowledgeList,
  saveAgent,
  submitAgentOfflineApproval,
  submitAgentPublishApproval,
  updateAgent,
  updateAgentKnowledgeBindings,
  updateAgentToolBindings,
} from './api';
import AgentStudioCanvas from './components/agent-studio/AgentStudioCanvas.vue';
import AgentCommandBar from './components/AgentCommandBar.vue';
import AgentInspectorPanel from './components/AgentInspectorPanel.vue';
import { useAgentDesignerState } from './composables/useAgentDesignerState';

const route = useRoute();
const router = useRouter();
const AGENT_TAB_PAGE_KEY = '/ai/agents';
const DEFAULT_AGENT_TITLE = '未命名智能体';
const {
  state,
  addKnowledgeNode,
  addToolNode,
  buildKnowledgePayload,
  buildPayloadAgent,
  buildToolPayload,
  markDirty,
  openTryout,
  removeSelectedCapability,
  reset,
  selectBase,
  selectNode,
  validate,
} = useAgentDesignerState();

const pageLoading = ref(false);
const saveLoading = ref(false);
const offlineLoading = ref(false);
const publishLoading = ref(false);
const issues = ref<AgentValidationIssue[]>([]);
const categories = ref<AgentOption[]>([]);
const models = ref<AgentOption[]>([]);
const knowledges = ref<AgentOption[]>([]);
const workflows = ref<AgentOption[]>([]);
const pluginTools = ref<AgentOption[]>([]);
const mcps = ref<AgentOption[]>([]);

const isNew = computed(() => String(route.params.id || '') === 'new');
const publishText = computed(() => {
  if (
    canAiResourceRepublish(
      state.agent.displayPublishStatus,
      state.agent.publishStatus,
    )
  ) {
    return '重新发布';
  }
  return '发布';
});

const offlineVisible = computed(() =>
  canAiResourceOffline(
    state.agent.displayPublishStatus,
    state.agent.publishStatus,
  ),
);

const publishDisabled = computed(() => {
  if (!state.agent.id) return true;
  if (
    isAiResourceApprovalPending(
      state.agent.displayPublishStatus,
      state.agent.publishStatus,
    )
  ) {
    return true;
  }
  return !(
    canAiResourcePublish(
      state.agent.displayPublishStatus,
      state.agent.publishStatus,
    ) ||
    canAiResourceRepublish(
      state.agent.displayPublishStatus,
      state.agent.publishStatus,
    )
  );
});

const offlineDisabled = computed(() => {
  if (!state.agent.id) return true;
  return !offlineVisible.value;
});

onMounted(async () => {
  pageLoading.value = true;
  try {
    await Promise.all([loadOptions(), loadAgent()]);
  } finally {
    pageLoading.value = false;
  }
});

async function loadAgent() {
  if (isNew.value) {
    reset();
    syncNavTitle(DEFAULT_AGENT_TITLE, { force: true });
    return;
  }
  const [, res] = await tryit(getAgentDetail)(String(route.params.id));
  if (res?.errorCode === 0) {
    reset(res.data);
    syncNavTitle(resolveAgentTitle(res.data), { force: !hasNavTitle() });
  }
}

async function refreshAgentLifecycleState() {
  if (!state.agent.id) return;
  const [, res] = await tryit(getAgentDetail)(String(state.agent.id));
  if (res?.errorCode !== 0 || !res.data) {
    return;
  }
  const agentState = { ...res.data };
  delete agentState.knowledgeBindings;
  delete agentState.toolBindings;
  state.agent = {
    ...state.agent,
    ...agentState,
  };
}

function hasNavTitle() {
  const navTitle = Array.isArray(route.query.navTitle)
    ? route.query.navTitle[0]
    : route.query.navTitle;
  return typeof navTitle === 'string' && navTitle.trim();
}

function resolveAgentTitle(agent = state.agent) {
  return String(agent.name || '').trim() || DEFAULT_AGENT_TITLE;
}

function syncNavTitle(title: string, options: { force?: boolean } = {}) {
  const normalizedTitle = String(title || '').trim() || DEFAULT_AGENT_TITLE;
  const query = route.query as Record<string, any>;
  const currentNavTitle = Array.isArray(query.navTitle)
    ? query.navTitle[0]
    : query.navTitle;
  const currentPageKey = Array.isArray(query.pageKey)
    ? query.pageKey[0]
    : query.pageKey;

  if (
    !options.force &&
    currentNavTitle === normalizedTitle &&
    currentPageKey === AGENT_TAB_PAGE_KEY
  ) {
    return;
  }

  router.replace({
    path: route.path,
    query: {
      ...query,
      pageKey: AGENT_TAB_PAGE_KEY,
      navTitle: normalizedTitle,
    },
  });
}

async function loadOptions() {
  const [categoryRes, modelRes, knowledgeRes, workflowRes, pluginRes, mcpRes] =
    await Promise.all([
      api.get('/api/v1/agentCategory/visibleList', {
        params: { sortKey: 'sortNo', sortType: 'asc' },
      }),
      getAgentModels(),
      getPublishedKnowledgeList(),
      api.get('/api/v1/workflow/page', {
        params: { pageNumber: 1, pageSize: 200 },
      }),
      api.get('/api/v1/plugin/pageByCategory', {
        params: { pageNumber: 1, pageSize: 200, category: 0 },
      }),
      api.get('/api/v1/mcp/pageTools', {
        params: { pageNumber: 1, pageSize: 200, status: 1 },
      }),
    ]);

  categories.value = (categoryRes.data || []).map((item: any) => ({
    label: item.categoryName || item.name,
    value: String(item.id),
    raw: item,
  }));
  models.value = (modelRes.data || []).map((item: any) => ({
    label: item.title || item.name,
    value: String(item.id),
    raw: item,
  }));
  knowledges.value = (knowledgeRes.data || []).map((item: any) => ({
    label: item.title || item.name,
    value: String(item.id),
    raw: item,
  }));
  workflows.value = (
    (workflowRes.data?.records || workflowRes.data || []) as any[]
  ).map((item) => ({
    label: item.title || item.name,
    value: String(item.id),
    raw: item,
  }));
  pluginTools.value = flattenPluginTools(
    pluginRes.data?.records || pluginRes.data || [],
  );
  mcps.value = mapMcpOptions(mcpRes.data?.records || mcpRes.data || []);
}

function flattenPluginTools(list: any[]): AgentOption[] {
  const result: AgentOption[] = [];
  list.forEach((plugin) => {
    const tools = Array.isArray(plugin.tools) ? plugin.tools : [];
    tools.forEach((tool: any) => {
      result.push({
        label: tool.name || tool.title,
        value: String(tool.id),
        raw: { ...tool, pluginName: plugin.name || plugin.title },
      });
    });
  });
  return result;
}

function mapMcpOptions(list: any[]): AgentOption[] {
  return list.map((mcp) => ({
    label: mcp.title || mcp.name || 'MCP',
    value: String(mcp.id),
    raw: {
      ...mcp,
      id: mcp.id,
      mcpId: mcp.id,
      mcpTitle: mcp.title || mcp.name,
      title: mcp.title || mcp.name,
      tools: Array.isArray(mcp.tools) ? mcp.tools : [],
      approvalRequired: Boolean(mcp.approvalRequired),
    },
  }));
}

async function handleAdd(kind: AgentCapabilityKind) {
  if (kind === 'knowledge') {
    addKnowledgeNode();
    return;
  }
  addToolNode(kind);
}

function handleSelectNode(nodeId: string) {
  selectNode(nodeId);
}

function handleSelectIssue(nodeId: string) {
  selectNode(nodeId);
}

function runValidation() {
  issues.value = validate();
  if (issues.value.length > 0) {
    selectNode(issues.value[0]!.nodeId);
    ElMessage.warning('请先完成必要配置');
    return false;
  }
  return true;
}

async function handleSave(showMessage = true) {
  if (!runValidation()) return false;
  saveLoading.value = true;
  try {
    const agentPayload = buildPayloadAgent();
    const agentRes = state.agent.id
      ? await updateAgent(agentPayload)
      : await saveAgent(agentPayload);
    if (agentRes.errorCode !== 0 || !agentRes.data?.id) {
      return false;
    }

    const id = agentRes.data.id;
    const toolBindingRes = await updateAgentToolBindings(
      id,
      buildToolPayload(id),
    );
    if (toolBindingRes.errorCode !== 0) {
      return false;
    }
    const knowledgeBindingRes = await updateAgentKnowledgeBindings(
      id,
      buildKnowledgePayload(id),
    );
    if (knowledgeBindingRes.errorCode !== 0) {
      return false;
    }

    state.agent = {
      ...state.agent,
      ...agentRes.data,
      id,
    };
    state.dirty = false;
    const title = resolveAgentTitle();
    if (isNew.value) {
      await router.replace({
        path: `/ai/agents/designer/${id}`,
        query: {
          ...route.query,
          pageKey: AGENT_TAB_PAGE_KEY,
          navTitle: title,
        },
      });
    } else {
      syncNavTitle(title, { force: true });
    }
    if (showMessage) {
      ElMessage.success('已保存');
    }
    return true;
  } finally {
    saveLoading.value = false;
  }
}

async function handlePublish() {
  if (!state.agent.id) return;
  const saved = await handleSave(false);
  if (!saved) return;

  try {
    await ElMessageBox.confirm('确认提交发布审批？', '提示', {
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      type: 'info',
    });
  } catch {
    return;
  }

  publishLoading.value = true;
  try {
    const res = await submitAgentPublishApproval(String(state.agent.id));
    if (res.errorCode === 0) {
      ElMessage.success(res.message || '已提交');
      await refreshAgentLifecycleState();
    }
  } finally {
    publishLoading.value = false;
  }
}

async function handleOffline() {
  if (!state.agent.id) return;
  const saved = await handleSave(false);
  if (!saved) return;

  try {
    await ElMessageBox.confirm('确认提交下线审批？', '提示', {
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      type: 'warning',
    });
  } catch {
    return;
  }

  offlineLoading.value = true;
  try {
    const res = await submitAgentOfflineApproval(String(state.agent.id));
    if (res.errorCode === 0) {
      ElMessage.success(res.message || '已提交');
      await refreshAgentLifecycleState();
    }
  } finally {
    offlineLoading.value = false;
  }
}

function handleTryout() {
  if (!runValidation()) return;
  openTryout();
}

function handleCloseTryout() {
  selectBase();
}
</script>

<template>
  <div v-loading="pageLoading" class="agent-designer">
    <AgentStudioCanvas
      :state="state"
      :knowledge-options="knowledges"
      :mcp-options="mcps"
      :plugin-options="pluginTools"
      :selected-node-id="state.selectedNodeId"
      :workflow-options="workflows"
      @select="handleSelectNode"
    />
    <AgentInspectorPanel
      :state="state"
      :models="models"
      :categories="categories"
      :knowledges="knowledges"
      :workflows="workflows"
      :plugin-tools="pluginTools"
      :mcps="mcps"
      :issues="issues"
      @change="markDirty"
      @remove-capability="removeSelectedCapability"
      @close-tryout="handleCloseTryout"
      @select-issue="handleSelectIssue"
    />
    <AgentCommandBar
      :save-loading="saveLoading"
      :publish-loading="publishLoading"
      :publish-disabled="publishDisabled"
      :publish-text="publishText"
      :offline-disabled="offlineDisabled"
      :offline-loading="offlineLoading"
      :offline-visible="offlineVisible"
      @add="handleAdd"
      @save="handleSave()"
      @offline="handleOffline"
      @publish="handlePublish"
      @tryout="handleTryout"
    />
  </div>
</template>

<style scoped>
.agent-designer {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  background:
    radial-gradient(
      circle at 50% 42%,
      var(--el-color-primary-light-9),
      transparent 32%
    ),
    var(--el-fill-color-extra-light);
}
</style>
