<script setup lang="ts">
import { computed, defineAsyncComponent, watch } from 'vue'
import { EVAL_METHODS, EVAL_METHOD_PROMPTS } from '@/constants/dimension'
import { DIMENSION_TYPE_MAP } from '@/constants'
import type { DimensionType, ModelItem } from '@/types'

// 编辑器体积较大，仅在用户进入包含 Prompt 的指标配置时加载。
const MdEditor = defineAsyncComponent(async () => {
  await import('md-editor-v3/lib/style.css')
  const module = await import('md-editor-v3')
  return module.MdEditor
})

export interface DimensionFormDraft {
  type: DimensionType | ''
  description: string
  eval_model: string
  eval_method: string | string[]
  eval_prompt: string
  is_active: boolean
  is_default: boolean
  bleu_n: number
  output_precision: number
  score_min: number
  score_max: number
  pass_threshold: number
}

const props = withDefaults(
  defineProps<{
    evalModels: ModelItem[]
    showDescription?: boolean
    showStatusSettings?: boolean
    allowedTypes?: DimensionType[]
  }>(),
  {
    showDescription: true,
    showStatusSettings: true,
    allowedTypes: () => ['classification', 'metric', 'text_similarity'],
  },
)

const form = defineModel<DimensionFormDraft>({ required: true })
const SCORE_STEP = 0.5

const typeOptions = computed(() =>
  Object.entries(DIMENSION_TYPE_MAP)
    .filter(([value]) => props.allowedTypes.includes(value as DimensionType))
    .map(([value, label]) => ({ value, label })),
)
const currentMethods = computed(() => (form.value.type ? EVAL_METHODS[form.value.type] || [] : []))

/**
 * 指标类型变化时初始化对应的评估方式和 Prompt。
 * 同步执行可保证编辑页批量回填时，接口返回值最终覆盖默认值。
 */
watch(
  () => form.value.type,
  (type) => {
    if (!type) return
    const firstMethod = EVAL_METHODS[type]?.[0]?.value || ''
    form.value.eval_method = type === 'text_similarity' ? [firstMethod] : firstMethod
    if (type !== 'text_similarity' && EVAL_METHOD_PROMPTS[firstMethod]) {
      form.value.eval_prompt = EVAL_METHOD_PROMPTS[firstMethod]
    }
  },
  { flush: 'sync' },
)

/** 评估方式变化时应用对应的预置 Prompt。 */
watch(
  () => form.value.eval_method,
  (method) => {
    if (form.value.type === 'text_similarity' || !method) return
    const selectedMethod = Array.isArray(method) ? method[0] : method
    if (selectedMethod && EVAL_METHOD_PROMPTS[selectedMethod]) {
      form.value.eval_prompt = EVAL_METHOD_PROMPTS[selectedMethod]
    }
  },
  { flush: 'sync' },
)

/** 始终保持评分区间合法，并把通过阈值收敛到当前区间内。 */
watch(
  () => [form.value.type, form.value.score_min, form.value.score_max] as const,
  ([type, scoreMin, scoreMax]) => {
    if (type !== 'metric') return
    if (scoreMax <= scoreMin) {
      form.value.score_max = scoreMin + SCORE_STEP
      return
    }
    form.value.pass_threshold = Math.min(
      Math.max(form.value.pass_threshold, scoreMin),
      scoreMax,
    )
  },
  { flush: 'sync' },
)
</script>

<template>
  <el-form-item label="指标类型" prop="type">
    <el-select v-model="form.type" placeholder="请选择指标类型" style="width: 100%">
      <el-option v-for="option in typeOptions" :key="option.value" :label="option.label" :value="option.value" />
    </el-select>
  </el-form-item>

  <el-form-item v-if="showDescription" label="描述">
    <el-input v-model="form.description" type="textarea" :rows="2" maxlength="200" show-word-limit />
  </el-form-item>

  <template v-if="form.type === 'classification' || form.type === 'metric'">
    <el-form-item label="选择大模型" prop="eval_model">
      <el-select v-model="form.eval_model" placeholder="请选择评测模型" filterable style="width: 100%">
        <el-option v-for="model in evalModels" :key="model.id" :label="model.name" :value="model.name" />
      </el-select>
    </el-form-item>

    <el-form-item label="评估方式" prop="eval_method">
      <el-radio-group v-model="(form.eval_method as string)">
        <el-radio v-for="method in currentMethods" :key="method.value" :value="method.value">
          {{ method.name }}
          <span class="method-desc">{{ method.desc }}</span>
        </el-radio>
      </el-radio-group>
    </el-form-item>

    <el-form-item label="评估 Prompt" prop="eval_prompt">
      <MdEditor
        v-model="form.eval_prompt"
        language="zh-CN"
        :toolbars-exclude="['github', 'save']"
        style="height: 320px"
      />
    </el-form-item>
  </template>

  <template v-if="form.type === 'text_similarity'">
    <el-form-item label="评估方式" prop="eval_method">
      <el-checkbox-group v-model="(form.eval_method as string[])">
        <el-checkbox v-for="method in currentMethods" :key="method.value" :value="method.value">
          {{ method.name }}
          <span class="method-desc">{{ method.desc }}</span>
        </el-checkbox>
      </el-checkbox-group>
    </el-form-item>

    <el-form-item label="BLEU n-gram">
      <el-select v-model="form.bleu_n" style="width: 160px">
        <el-option :value="1" label="1-gram" />
        <el-option :value="2" label="2-gram" />
        <el-option :value="3" label="3-gram" />
        <el-option :value="4" label="4-gram" />
      </el-select>
    </el-form-item>

    <el-form-item label="输出精度">
      <el-select v-model="form.output_precision" style="width: 160px">
        <el-option :value="1" label="1 位小数" />
        <el-option :value="2" label="2 位小数" />
        <el-option :value="3" label="3 位小数" />
        <el-option :value="4" label="4 位小数" />
      </el-select>
    </el-form-item>
  </template>

  <template v-if="form.type === 'metric'">
    <el-form-item label="评分最小值" prop="score_min">
      <el-input-number
        v-model="form.score_min"
        :min="0"
        :max="Math.max(form.score_max - SCORE_STEP, 0)"
        :step="SCORE_STEP"
        style="width: 160px"
      />
    </el-form-item>
    <el-form-item label="评分最大值" prop="score_max">
      <el-input-number
        v-model="form.score_max"
        :min="form.score_min + SCORE_STEP"
        :step="SCORE_STEP"
        style="width: 160px"
      />
    </el-form-item>
    <el-form-item label="通过阈值" prop="pass_threshold">
      <div style="width: 100%">
        <el-slider
          v-model="form.pass_threshold"
          :min="form.score_min"
          :max="form.score_max"
          :step="0.5"
          show-input
          :show-input-controls="false"
        />
      </div>
    </el-form-item>
  </template>

  <template v-if="showStatusSettings">
    <el-form-item label="启用该维度">
      <el-switch v-model="form.is_active" />
    </el-form-item>
    <el-form-item label="设为默认">
      <el-switch v-model="form.is_default" />
    </el-form-item>
  </template>
</template>

<style scoped>
.method-desc {
  color: #909399;
  font-size: 12px;
  margin-left: 6px;
}
</style>
