import { Injectable } from '@nestjs/common';
import type { AiCall } from '../../ai-call.interface';
import type { SafetyRule } from '../../core/safety-gate.service';
import { DraftRecallSummarySchema } from './schema';
import type { DraftRecallSummaryInput, DraftRecallSummaryOutput } from './input.types';
import {
  DRAFT_RECALL_SUMMARY_PROMPT_VERSION,
  DRAFT_RECALL_SUMMARY_SYSTEM,
  buildDraftRecallSummaryPrompt,
} from './prompt';

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

const safetyRules: ReadonlyArray<SafetyRule<DraftRecallSummaryOutput>> = [
  {
    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 拒收时:用记录拼一句最朴素的概述。
 *
 * ⭐「最近一次」必须取 isLatestPast 那条,**不能**取 items[0] —— items 按日期倒序,
 *   头部很可能是尚未到期的未来排程,拿它当"最近一次"就是 2026-07 那次生产事故的原样复刻
 *   (兜底文案同样会展示给客服)。全是未来排程时不提"最近一次"。
 */
function fallback(input: DraftRecallSummaryInput): DraftRecallSummaryOutput {
  const n = input.items.length;
  if (n === 0) return { summary: '暂无历史联系记录。' };
  const latest = input.items.find((it) => it.isLatestPast);
  if (!latest) return { summary: `共 ${n} 条历史联系,均为尚未到期的排程。` };
  const what = [latest.type, latest.status].filter(Boolean).join(' · ') || '回访';
  const outcome = latest.result?.trim() || latest.followContent?.trim();
  const tail = outcome ? `,${outcome.slice(0, 20)}` : ',未留结果';
  return { summary: `共 ${n} 条历史联系,最近一次:${latest.taskDate ?? '—'} ${what}${tail}。` };
}

@Injectable()
export class DraftRecallSummaryCall
  implements AiCall<DraftRecallSummaryInput, DraftRecallSummaryOutput>
{
  readonly kind = 'summary' as const;
  readonly callKey = 'draft_recall_summary';
  readonly promptVersion = DRAFT_RECALL_SUMMARY_PROMPT_VERSION;
  readonly defaultModelId = 'qwen'; // 这类一句话摘要统一走 Qwen(qwen3.7-max)
  readonly outputSchema = DraftRecallSummarySchema;
  readonly safetyRules = safetyRules;

  buildPrompt(input: DraftRecallSummaryInput) {
    return {
      system: DRAFT_RECALL_SUMMARY_SYSTEM,
      prompt: buildDraftRecallSummaryPrompt(input),
    };
  }

  fallback(input: DraftRecallSummaryInput): DraftRecallSummaryOutput {
    return fallback(input);
  }
}
