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 = [
  '你是资深口腔回访话术规划师。基于给定的患者事实,规划一通"医疗关怀回访"电话:拆成几段、每段讲什么。',
  '原则:医疗关怀非销售;以本次聚焦项(应治未治)为主线,其他牙问题 / 历史联系 / 价值维系可一并关心(值得就单独开段讲);每个要点都必须能追到给定事实,不编造。',
  '不要写话术正文,只输出大纲 JSON。**段数和结构由你按这通电话实际要覆盖的来定**(一般 3-7 段):料多(多颗牙 / 历史联系 / 高价值维系)就多开段讲透,料少就精简——不必套固定段式。',
].join('\n');

const VERIFY_SYSTEM = [
  '你是严格的医疗话术审核员,任务是**对抗式校验**一份回访话术草稿,默认怀疑、宁严勿松。',
  '只依据给定的"本次回访患者信息"判断:',
  '① 接地:草稿每个具体说法(诊断/检查所见/医嘱/时间/牙位/医生)能否在给定事实里找到依据?找不到=编造。',
  '② 安全:有无报价/费用、疗效承诺、写死具体时间(应保留【时间段】)、患者≤18 却提拍片?',
  '全部通过 → pass=true、issues 空;任一不过 → pass=false 并逐条列出 issue(段、问题、修法)。',
  '另外给一组 **quality 质量评分**(1-5:口语自然 / 关怀温度 / 聚焦 / 不推销 + overall 综合)—— **只评"好不好",跟 pass 无关**(接地+安全才决定 pass;写得平庸但合规,pass 仍可 true,quality 给低分即可)。',
  '只输出 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-08-deep-plan-v7'; // v7: schema 去硬约束(.min/.max → describe);v2: 去 {} 替换占位(朴素 labeled facts)
  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-08-deep-write-v12'; // v12: schema 去硬约束(.min/.max → describe);v11: repair 喂上一稿 + 逐条强约束(严格按自检 fix 改)
  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-08-deep-verify-v7'; // v7: schema 去硬约束(.min/.max/.int → describe);v2: 去 {} 替换占位(随 fact-block)
  readonly defaultModelId = 'deepseek-v4-flash';
  readonly outputSchema = DeepVerifySchema;
  buildPrompt(input: DeepVerifyInput) {
    return { system: VERIFY_SYSTEM, prompt: buildVerifyPrompt(input) };
  }
}
