<script setup lang="ts">
/* eslint-disable vue/no-mutating-props */
import type { AgentInfo, AgentOption, AgentToolBinding } from '../types';

import { InfoFilled } from '@element-plus/icons-vue';
import {
  ElForm,
  ElFormItem,
  ElIcon,
  ElInput,
  ElInputNumber,
  ElOption,
  ElSelect,
  ElSwitch,
  ElTooltip,
} from 'element-plus';

import { resolveAgentCompressionTokenThreshold } from '../compression-threshold';

const props = defineProps<{
  agent: AgentInfo;
  categories: AgentOption[];
  models: AgentOption[];
  toolBindings: AgentToolBinding[];
}>();

const emit = defineEmits<{ change: [] }>();

function handleModelChange(modelId: AgentInfo['modelId']) {
  const selectedModel = props.models.find(
    (model) => model.value === String(modelId ?? ''),
  );
  const memoryConfig = (props.agent.memoryConfigJson ||= {});
  const compressionParameter = (memoryConfig.compressionParameter ||= {});
  compressionParameter.minCompressionTokenThreshold =
    resolveAgentCompressionTokenThreshold({
      contextWindowTokens: selectedModel?.raw?.contextWindowTokens,
      generationConfig: props.agent.generationConfigJson,
      maxOutputTokens: selectedModel?.raw?.maxOutputTokens,
      systemPrompt: props.agent.promptConfigJson?.systemPrompt,
      toolBindings: props.toolBindings,
    });
  emit('change');
}
</script>

<template>
  <ElForm label-position="top" class="agent-form">
    <ElFormItem label="名称" required>
      <ElInput
        v-model="agent.name"
        maxlength="50"
        show-word-limit
        @input="emit('change')"
      />
    </ElFormItem>
    <ElFormItem label="描述">
      <ElInput
        v-model="agent.description"
        type="textarea"
        :rows="3"
        maxlength="200"
        show-word-limit
        @input="emit('change')"
      />
    </ElFormItem>
    <ElFormItem label="头像">
      <ElInput
        v-model="agent.avatar"
        placeholder="图片地址"
        @input="emit('change')"
      />
    </ElFormItem>
    <ElFormItem label="分类">
      <ElSelect
        v-model="agent.categoryId"
        clearable
        filterable
        @change="emit('change')"
      >
        <ElOption
          v-for="item in categories"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </ElSelect>
    </ElFormItem>
    <ElFormItem label="模型" required>
      <ElSelect v-model="agent.modelId" filterable @change="handleModelChange">
        <ElOption
          v-for="item in models"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </ElSelect>
    </ElFormItem>
    <ElFormItem>
      <template #label>
        <span class="agent-form__label">
          模型流式响应
          <ElTooltip
            content="关闭后，模型会在生成完成后一次性返回回答。"
            effect="light"
            placement="top"
          >
            <ElIcon class="agent-form__info" aria-label="模型流式响应说明">
              <InfoFilled />
            </ElIcon>
          </ElTooltip>
        </span>
      </template>
      <ElSwitch
        v-model="agent.generationConfigJson!.stream"
        aria-label="模型流式响应"
        @change="emit('change')"
      />
    </ElFormItem>
    <ElFormItem>
      <template #label>
        <span class="agent-form__label">
          文档上下文预算
          <ElTooltip
            :trigger-keys="['Enter', 'Space']"
            content="控制单次对话最多注入多少文档内容，建议设置为 20K Token 或以上。数值过低可能导致长文档仅读取部分内容，影响回答完整性；请确保该值未超过模型的实际上下文能力。"
            effect="light"
            placement="top"
          >
            <ElIcon
              class="agent-form__info"
              aria-label="文档上下文预算说明"
              tabindex="0"
            >
              <InfoFilled />
            </ElIcon>
          </ElTooltip>
        </span>
      </template>
      <ElInputNumber
        v-model="agent.executionConfigJson!.documentContextBudgetTokens"
        :min="1"
        :step="1000"
        controls-position="right"
        aria-label="文档上下文预算 Token 数"
        @change="emit('change')"
      />
      <div
        v-if="
          Number(agent.executionConfigJson!.documentContextBudgetTokens) <
          20_000
        "
        class="agent-form__hint is-warning"
      >
        建议设置为 20K Token 或以上
      </div>
    </ElFormItem>
    <ElFormItem label="系统提示词">
      <ElInput
        v-model="agent.promptConfigJson!.systemPrompt"
        type="textarea"
        :rows="7"
        @input="emit('change')"
      />
    </ElFormItem>
    <div class="agent-form__grid">
      <ElFormItem>
        <template #label>
          <span class="agent-form__label">
            最近保留消息数
            <ElTooltip
              content="压缩上下文时，最近这 N 条消息会尽量保留原文；更早的消息会优先被压缩。"
              effect="light"
              placement="top"
            >
              <ElIcon class="agent-form__info" aria-label="最近保留消息数说明">
                <InfoFilled />
              </ElIcon>
            </ElTooltip>
          </span>
        </template>
        <ElInputNumber
          v-model="agent.memoryConfigJson!.compressionParameter.lastKeep"
          :min="0"
          :max="100"
          controls-position="right"
          @change="emit('change')"
        />
      </ElFormItem>
      <ElFormItem>
        <template #label>
          <span class="agent-form__label">
            最小压缩 Token 阈值
            <ElTooltip
              content="选择模型时按上下文 85% 与扣除输出、系统提示词、工具和安全余量后的可用值取较小值；模型目录未提供上下文时使用 30K。"
              effect="light"
              placement="top"
            >
              <ElIcon
                class="agent-form__info"
                aria-label="最小压缩 Token 阈值说明"
              >
                <InfoFilled />
              </ElIcon>
            </ElTooltip>
          </span>
        </template>
        <ElInputNumber
          v-model="
            agent.memoryConfigJson!.compressionParameter
              .minCompressionTokenThreshold
          "
          :min="0"
          :step="500"
          controls-position="right"
          @change="emit('change')"
        />
      </ElFormItem>
    </div>
  </ElForm>
</template>

<style scoped>
.agent-form {
  padding: 16px;
}

.agent-form__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}

.agent-form__label {
  display: inline-flex;
  gap: 4px;
  align-items: center;
}

.agent-form__info {
  font-size: 14px;
  color: var(--el-text-color-secondary);
  cursor: help;
}

.agent-form__hint {
  margin-top: 4px;
  font-size: 12px;
  line-height: 20px;
}

.agent-form__hint.is-warning {
  color: var(--el-color-warning);
}

.agent-form :deep(.el-select),
.agent-form :deep(.el-input-number) {
  width: 100%;
}
</style>
