<script setup lang="ts">
import type {
  AgentDraftState,
  AgentOption,
  AgentValidationIssue,
} from '../types';

import {
  computed,
  defineAsyncComponent,
  nextTick,
  onBeforeUnmount,
  onMounted,
  ref,
  watch,
} from 'vue';

import { Close } from '@element-plus/icons-vue';
import { ElButton, ElTabPane, ElTabs } from 'element-plus';

import AgentBaseForm from './AgentBaseForm.vue';

const props = defineProps<{
  categories: AgentOption[];
  issues: AgentValidationIssue[];
  knowledges: AgentOption[];
  mcps: AgentOption[];
  mcpToolsLoading: Record<string, boolean>;
  models: AgentOption[];
  pluginTools: AgentOption[];
  state: AgentDraftState;
  workflows: AgentOption[];
}>();

const emit = defineEmits<{
  change: [];
  closeTryout: [];
  loadMcpTools: [id: string];
  removeCapability: [];
  selectIssue: [nodeId: string];
}>();

const loadAgentInteractionForm = () => import('./AgentInteractionForm.vue');
const loadAgentKnowledgeForm = () => import('./AgentKnowledgeForm.vue');
const loadAgentToolForm = () => import('./AgentToolForm.vue');
const loadAgentTryoutPanel = () => import('./AgentTryoutPanel.vue');
const AgentInteractionForm = defineAsyncComponent(loadAgentInteractionForm);
const AgentKnowledgeForm = defineAsyncComponent(loadAgentKnowledgeForm);
const AgentToolForm = defineAsyncComponent(loadAgentToolForm);
const AgentTryoutPanel = defineAsyncComponent(loadAgentTryoutPanel);

interface AgentInteractionFormExpose {
  focusField: (field: string) => Promise<void> | void;
}

const selectedKnowledge = computed(() => {
  if (!props.state.selectedNodeId.startsWith('knowledge:')) return;
  const localId = props.state.selectedNodeId.slice('knowledge:'.length);
  return props.state.knowledgeBindings.find((item) => item.localId === localId);
});

const activeBaseTab = ref<'basic' | 'interaction'>('basic');
const interactionForm = ref<AgentInteractionFormExpose>();
const selectedModel = computed(() =>
  props.models.find((item) => item.value === String(props.state.agent.modelId)),
);
const tryoutImageEnabled = computed(() =>
  Boolean(selectedModel.value?.raw?.supportImage),
);

function isInteractionIssue(issue?: AgentValidationIssue) {
  return issue?.field?.startsWith('interaction.');
}

async function focusIssue(issue: AgentValidationIssue) {
  if (issue.nodeId !== 'agent-base') return;
  activeBaseTab.value = isInteractionIssue(issue) ? 'interaction' : 'basic';
  if (isInteractionIssue(issue) && issue.field) {
    await nextTick();
    await interactionForm.value?.focusField(issue.field);
  }
}

function handleIssueClick(issue: AgentValidationIssue) {
  void focusIssue(issue);
  emit('selectIssue', issue.nodeId);
}

watch(
  () => props.issues,
  (issues) => {
    const firstIssue = issues[0];
    if (firstIssue?.nodeId === 'agent-base') void focusIssue(firstIssue);
  },
  { deep: true },
);

const selectedTool = computed(() => {
  if (!props.state.selectedNodeId.startsWith('tool:')) return;
  const localId = props.state.selectedNodeId.slice('tool:'.length);
  return props.state.toolBindings.find((item) => item.localId === localId);
});

const selectedToolKind = computed(() => {
  const toolType = String(selectedTool.value?.toolType || '').toUpperCase();
  if (toolType === 'WORKFLOW') return 'workflow';
  if (toolType === 'MCP') return 'mcp';
  return 'plugin';
});

const selectedToolOptions = computed(() => {
  if (selectedToolKind.value === 'workflow') return props.workflows;
  if (selectedToolKind.value === 'mcp') return props.mcps;
  return props.pluginTools;
});

watch(
  () =>
    selectedToolKind.value === 'mcp'
      ? String(selectedTool.value?.targetId || '')
      : '',
  (mcpId) => {
    if (mcpId) {
      emit('loadMcpTools', mcpId);
    }
  },
  { immediate: true },
);

let prefetchHandle: number | undefined;
let prefetchTimer: number | undefined;

onMounted(() => {
  const prefetchHiddenPanels = () => {
    void Promise.allSettled([
      loadAgentInteractionForm(),
      loadAgentKnowledgeForm(),
      loadAgentToolForm(),
      loadAgentTryoutPanel(),
    ]);
  };
  if (typeof window.requestIdleCallback === 'function') {
    prefetchHandle = window.requestIdleCallback(prefetchHiddenPanels, {
      timeout: 3000,
    });
    return;
  }
  prefetchTimer = window.setTimeout(prefetchHiddenPanels, 1000);
});

onBeforeUnmount(() => {
  if (prefetchHandle !== undefined) {
    window.cancelIdleCallback(prefetchHandle);
  }
  if (prefetchTimer !== undefined) {
    window.clearTimeout(prefetchTimer);
  }
});
</script>

<template>
  <aside class="agent-inspector">
    <template v-if="state.panelMode === 'tryout'">
      <AgentTryoutPanel
        :agent="state.agent"
        :image-enabled="tryoutImageEnabled"
        :tool-bindings="state.toolBindings"
        :knowledge-bindings="state.knowledgeBindings"
        @close="emit('closeTryout')"
      />
    </template>
    <template v-else>
      <header class="agent-inspector__header">
        <div>
          <div class="agent-inspector__title">
            {{ state.panelMode === 'base' ? '基座智能体' : '能力配置' }}
          </div>
          <div class="agent-inspector__subtitle">
            {{ state.panelMode === 'base' ? '核心设定' : '绑定关系' }}
          </div>
        </div>
      </header>

      <div class="agent-inspector__body">
        <div v-if="issues.length > 0" class="agent-inspector__issues">
          <button
            v-for="issue in issues"
            :key="`${issue.nodeId}-${issue.field || issue.message}`"
            class="agent-inspector__issue"
            type="button"
            @click="handleIssueClick(issue)"
          >
            {{ issue.message }}
          </button>
        </div>

        <template v-if="state.panelMode === 'base'">
          <ElTabs v-model="activeBaseTab" class="agent-inspector__tabs">
            <ElTabPane label="基础设置" name="basic">
              <AgentBaseForm
                :agent="state.agent"
                :categories="categories"
                :models="models"
                @change="emit('change')"
              />
            </ElTabPane>
            <ElTabPane label="对话体验" name="interaction">
              <AgentInteractionForm
                ref="interactionForm"
                :agent="state.agent"
                @change="emit('change')"
              />
            </ElTabPane>
          </ElTabs>
        </template>
        <AgentKnowledgeForm
          v-else-if="selectedKnowledge"
          :binding="selectedKnowledge"
          :knowledges="knowledges"
          @change="emit('change')"
          @remove="emit('removeCapability')"
        />
        <AgentToolForm
          v-else-if="selectedTool"
          :binding="selectedTool"
          :kind="selectedToolKind"
          :mcp-tools-loading="
            Boolean(mcpToolsLoading[String(selectedTool.targetId || '')])
          "
          :options="selectedToolOptions"
          @change="emit('change')"
          @remove="emit('removeCapability')"
        />
        <div v-else class="agent-inspector__empty">
          <ElButton :icon="Close" text @click="emit('closeTryout')">
            返回基座
          </ElButton>
        </div>
      </div>
    </template>
  </aside>
</template>

<style scoped>
.agent-inspector {
  position: absolute;
  top: 24px;
  right: 24px;
  bottom: 96px;
  z-index: 20;
  display: flex;
  flex-direction: column;
  width: min(420px, calc(100vw - 320px));
  min-height: 0;
  overflow: hidden;
  background: var(--el-bg-color);
  background: color-mix(in srgb, var(--el-bg-color) 94%, transparent);
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 8px;
  box-shadow: var(--el-box-shadow-light);
  backdrop-filter: blur(16px);
}

.agent-inspector__header {
  padding: 16px;
  border-bottom: 1px solid var(--el-border-color-lighter);
}

.agent-inspector__body {
  flex: 1;
  min-height: 0;
  overflow: hidden auto;
  overscroll-behavior: contain;
}

.agent-inspector__title {
  font-size: 16px;
  font-weight: 600;
}

.agent-inspector__subtitle {
  margin-top: 4px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
}

.agent-inspector__issues {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 16px 0;
}

.agent-inspector__issue {
  padding: 8px 10px;
  font-size: 12px;
  color: var(--el-color-danger);
  text-align: left;
  cursor: pointer;
  background: var(--el-color-danger-light-9);
  border: 0;
  border-radius: 8px;
}

.agent-inspector__tabs :deep(.el-tabs__header) {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: 0 var(--space-4);
  margin: 0;
  background: hsl(var(--surface-panel));
  border-bottom: 1px solid hsl(var(--line-subtle));
}

.agent-inspector__tabs :deep(.el-tabs__nav-wrap::after) {
  display: none;
}

.agent-inspector__empty {
  padding: 16px;
}
</style>
