import { Injectable } from '@nestjs/common';
import type { AiCall } from '../../ai-call.interface';
import type { SafetyRule } from '../../core/safety-gate.service';
import { DraftRecallBriefSchema } from './schema';
import type { DraftRecallBriefInput, DraftRecallBriefOutput } from './input.types';
import {
  DRAFT_RECALL_BRIEF_PROMPT_VERSION,
  DRAFT_RECALL_BRIEF_SYSTEM,
  buildDraftRecallBriefPrompt,
} from './prompt';

const FORBIDDEN_PHRASES = ['一定能', '保证', '绝对', '百分百', '100%', '亲爱的'];

const safetyRules: ReadonlyArray<SafetyRule<DraftRecallBriefOutput>> = [
  {
    name: 'no_forbidden_phrases',
    severity: 'block',
    check(output) {
      const hit = FORBIDDEN_PHRASES.filter((p) => output.summary.includes(p));
      return { pass: hit.length === 0, message: hit.length > 0 ? `命中禁词: ${hit.join(',')}` : undefined };
    },
  },
];

/** LLM 失败 / safety 拒收时:用召回原因拼一句最朴素的简报。 */
function fallback(input: DraftRecallBriefInput): DraftRecallBriefOutput {
  const r = input.reasons[0];
  if (!r) return { summary: '暂无明确召回原因。' };
  const cats = r.expectedCategories.join(' / ');
  const parts = [
    r.tooth ? `${r.tooth}` : null,
    r.diagnosis,
    `${r.daysSinceText}前`,
    cats ? `未启动 ${cats}` : null,
  ].filter(Boolean);
  // 切入尾巴(第④问,按优先级):医生计划/建议/医嘱(带原话) > 洁牙锚点(带时间) > 通用复查邀约
  const g0 = input.doctorGuidance.find((g) => g.verbatim) ?? input.doctorGuidance[0];
  const KIND_VERB = { plan: '已有计划', recommendation: '建议过', advice: '医嘱交代过' } as const;
  const entry = g0
    ? `;医生${KIND_VERB[g0.kind]}${g0.verbatim ? `「${g0.verbatim}」` : g0.label},可约复查跟进`
    : input.reviewAnchors.lastCleaningText
      ? `;距上次洁牙/检查 ${input.reviewAnchors.lastCleaningText},可约复查切入`
      : ';可约复查请医生评估';
  return { summary: `${r.subLabel}:${parts.join(' · ')}${entry}。` };
}

@Injectable()
export class DraftRecallBriefCall
  implements AiCall<DraftRecallBriefInput, DraftRecallBriefOutput>
{
  readonly kind = 'summary' as const;
  readonly callKey = 'draft_recall_brief';
  readonly promptVersion = DRAFT_RECALL_BRIEF_PROMPT_VERSION;
  readonly defaultModelId = 'qwen'; // 这类一句话摘要统一走 Qwen(qwen3.7-max)
  readonly outputSchema = DraftRecallBriefSchema;
  readonly safetyRules = safetyRules;

  buildPrompt(input: DraftRecallBriefInput) {
    return {
      system: DRAFT_RECALL_BRIEF_SYSTEM,
      prompt: buildDraftRecallBriefPrompt(input),
    };
  }

  fallback(input: DraftRecallBriefInput): DraftRecallBriefOutput {
    return fallback(input);
  }
}
