import { Injectable } from '@nestjs/common';
import type { AiCall } from '../../../../ai-call.interface';
import type { ScriptContext } from '../../shared/input.types';
import { composeSystem } from '../../shared/skill-composer';
import { DraftPlanScriptSkillRegistry } from '../../shared/skill-registry.service';
import { DeepPlanSchema, DeepWriteSchema, DeepVerifySchema, type DeepPlanZ, type DeepWriteZ, type DeepVerifyZ } from './schema';
import { buildPlanPrompt, buildWritePrompt, buildVerifyPrompt } from './prompts';
import { draftOutputToDeep, type DeepWriteInput, type DeepVerifyInput } from './types';
import { stableTemplateFallback } from '../stable/stable.call';

/**
 * 深度档 3 个 AiCall(都过 AiCallRunner,各自落 agent_invocations;由 DeepScriptStrategy 串联)。
 *   plan(规划)→ write(写,多段)→ verify(独立对抗校验)。
 * 三者 callKey 各异(eval 可分别看);共享 ScriptContext / runner / 安全函数。
 * write 用 composeSystem(...,'deep') 装配话术 system;plan/verify 是内部推理步,system 内联。
 */

const PLAN_SYSTEM = [
  '你是资深口腔回访话术规划师。基于给定的患者事实,规划一通"医疗关怀回访"电话:拆成几段、每段讲什么。',
  '原则:医疗关怀非销售;以本次聚焦项(应治未治)为主线,其他牙问题 / 历史联系 / 价值维系可一并关心(值得就单独开段讲);每个要点都必须能追到给定事实,不编造。',
  '',
  '# 规划方法:从果(目标)倒推到因',
  '先定这通电话的"果"——目标是让患者明白"该回来把 X 处理掉、早处理的好处 / 拖着的后果",从而愿意来复查;',
  '再倒推"因"——为达成这个目标,患者需要先知道什么、被打消什么顾虑:当前是什么缺口、为什么重要、不处理会怎样、来了能解决什么。',
  '据此把这条"因 → 果"的链条拆成层层递进的段落。',
  '',
  '# 结构:层层递进、逻辑层次清晰',
  '段与段是递进关系,不是并列罗列——前一段为后一段铺垫、后一段顺前一段往下推。**具体分几段、每段讲什么、怎么排,由你按这通电话的料自己定,不必套固定段式。**',
  '每段的 intent 写清它承上启下做什么,让审核能看出递进逻辑。',
  '',
  '# 说明风险的分寸:把后果讲清,但不吓唬、不推销',
  '"不处理会怎样"要**客观说明**(结合病历 + 牙科常识,如 缺牙久拖邻牙移位 / 龋齿不补伤神经),让患者理解严重性;',
  '但**不夸大、不制造恐慌、不下吓人结论**(别说"会掉光""很危险"这类),也**不报价、不促单、不施压**——目的是让患者为自己着想地决定来,不是被吓来或被推销来。',
  '',
  '不要写话术正文,只输出大纲 JSON。**段数由这通电话实际要覆盖的料来定,控制在 3-6 段**:料多(多颗牙 / 历史联系 / 高价值维系)就多开段讲透但不超 6 段,料少就精简到 3 段——不必套固定段式。',
].join('\n');

const VERIFY_SYSTEM = [
  '你是严格的医疗话术审核员,任务是**对抗式校验**一份回访话术草稿,默认怀疑、宁严勿松。',
  '依据给定的"本次回访患者信息"逐项判断:',
  '① 接地:草稿每个具体说法(诊断/检查所见/医嘱/时间/牙位/医生)能否在给定事实里找到依据?找不到=编造。',
  '② 安全:有无报价/费用、疗效承诺、写死具体时间(应保留【时间段】)、患者≤18 却提拍片?',
  '③ 逻辑与分寸:',
  '   - 从果推因:是否围绕"让患者明白该回来处理"展开,而不是东拉西扯;',
  '   - 层层递进:段与段是否层层递进、承上启下,还是并列罗列、跳跃、重复;',
  '   - 逻辑层次清晰:有没有该说的没说(如点了问题却没说不处理的后果、说了后果却没给到诊解决的出路);',
  '   - 把后果说清但不越界:不处理的后果是否客观说明了;有没有**吓唬/制造恐慌**(如"会掉光""很危险"式吓人结论)或**推销/促单/施压**口吻。',
  '④ 患者听得懂:有没有患者听不懂的东西——**诊断代码(如 K08)、英文/内部枚举、生硬专业术语**,或含糊其辞("上小磨牙或下小磨牙"这种没说清哪颗)?有 = 记 issue,要求改成大白话/说清。',
  '①②③④ 任一不过 → pass=false,并逐条列出 issue(段、问题、修法);全部通过 → pass=true、issues 空。',
  '另外给一组 **quality 质量评分**(1-5:口语自然 / 关怀温度 / 聚焦 / 不推销 + overall 综合)—— **只评"好不好",跟 pass 无关**。',
  '只输出 JSON,不改写草稿。',
].join('\n');

@Injectable()
export class DeepPlanCall implements AiCall<ScriptContext, DeepPlanZ> {
  readonly kind = 'script' as const;
  readonly callKey = 'draft_plan_script_plan';
  readonly promptVersion = 'draft_plan_script@2026-06-16-deep-plan-v9'; // v9: 去掉钦定段式(给自由度),只留从果推因/层层递进原则;v8: 从果推因+后果不吓唬+3-6段
  readonly defaultModelId = 'deepseek-v4-flash';
  readonly outputSchema = DeepPlanSchema;
  buildPrompt(ctx: ScriptContext) {
    return { system: PLAN_SYSTEM, prompt: buildPlanPrompt(ctx) };
  }
}

@Injectable()
export class DeepWriteCall implements AiCall<DeepWriteInput, DeepWriteZ> {
  readonly kind = 'script' as const;
  readonly callKey = 'draft_plan_script_write';
  readonly promptVersion = 'draft_plan_script@2026-06-16-deep-write-v18'; // v18: 低龄约束(<18 不主推种植)+ 替牙期(≤12)说「早期矫治」。v17: 高龄硬约束(≥75 缺牙禁推种植/手术)。v16: 自报家门去人名 → 占位【回访客服】(渲染期按登录人回填,修串名 bug)。v15: 去掉钦定段式(给自由度);v14: 禁内部代码/术语(K08等)说大白话
  readonly defaultModelId = 'deepseek-v4-flash';
  readonly outputSchema = DeepWriteSchema;
  constructor(private readonly skillRegistry: DraftPlanScriptSkillRegistry) {}
  buildPrompt(input: DeepWriteInput) {
    const composed = composeSystem(input.ctx, this.skillRegistry.getAllSkills(), 'deep');
    return { system: composed.systemPrompt, prompt: buildWritePrompt(input) };
  }
  // 写步失败/拒收 → 回退稳健模板(转多段),保证客服永远有东西可用
  fallback(input: DeepWriteInput): DeepWriteZ {
    return draftOutputToDeep(stableTemplateFallback(input.ctx));
  }
}

@Injectable()
export class DeepVerifyCall implements AiCall<DeepVerifyInput, DeepVerifyZ> {
  readonly kind = 'judge' as const;
  readonly callKey = 'draft_plan_script_verify';
  readonly promptVersion = 'draft_plan_script@2026-06-16-deep-verify-v10'; // v10: 递进检查去钦定段式(给自由度);v9: 加④患者听得懂(无代码/术语/含糊)
  readonly defaultModelId = 'deepseek-v4-flash';
  readonly outputSchema = DeepVerifySchema;
  buildPrompt(input: DeepVerifyInput) {
    return { system: VERIFY_SYSTEM, prompt: buildVerifyPrompt(input) };
  }
}
