import { Injectable } from '@nestjs/common';
import { PlanScriptOrchestrator } from '../ai/orchestrators/plan-script.orchestrator';
import { DraftPlanScriptSkillRegistry } from '../ai/calls/draft-plan-script/skill-registry.service';
import { composeSystem } from '../ai/calls/draft-plan-script/skill-composer';
import type { DraftPlanScriptInput } from '../ai/calls/draft-plan-script/input.types';
import {
  REALTIME_COACH_ROLE_HEADER,
  REALTIME_COACH_KNOWLEDGE_HEADER,
  REALTIME_COACH_OUTPUT_CONSTRAINTS,
} from './coach-prompts';

/**
 * RealtimeCoachContextService — 给 Qwen-Omni-Realtime 装配 instructions。
 *
 * 复用的是【患者上下文装配管线】(PlanScriptOrchestrator.buildScriptInputForPlan + composeSystem
 * 选中的 skills 列表),**但不注入 skill body** —— PAC 的 skills 本质是"邀约到店"的召回销售脚本,
 * 拿来当教练知识会把它变成推销机器(实测如此)。教练只需:患者临床事实 + 人情味教练指令;
 * 牙科常识模型自带。composeSystem 仍用于得出"哪些 skills 相关"(给面板展示 skills tag)。
 */
@Injectable()
export class RealtimeCoachContextService {
  constructor(
    private readonly planScriptOrchestrator: PlanScriptOrchestrator,
    private readonly skillRegistry: DraftPlanScriptSkillRegistry,
  ) {}

  async buildInstructions(planId: string): Promise<{ instructions: string; skills: string[] }> {
    const input = await this.planScriptOrchestrator.buildScriptInputForPlan(planId);
    const composed = composeSystem(input, this.skillRegistry.getAllSkills());

    // skill body 作为"专业知识"注入,但排除 scenario-*(那是"一步到位约到店"的召回剧本,
    // 会盖过"抓主诉、循序渐进"的口径);保留 diagnosis / objection / relationship / population / safety。
    const knowledgeBlock = composed.matchedSkills
      .filter((s) => !s.frontmatter.name.startsWith('scenario-'))
      .map((s) => `## [${s.frontmatter.name}]\n${s.body}`)
      .join('\n\n---\n\n');

    const instructions = [
      REALTIME_COACH_ROLE_HEADER,
      this.buildPatientContextBlock(input),
      knowledgeBlock ? `${REALTIME_COACH_KNOWLEDGE_HEADER}\n\n${knowledgeBlock}` : '',
      REALTIME_COACH_OUTPUT_CONSTRAINTS, // 输出约束放最后,最近最强
    ]
      .filter(Boolean)
      .join('\n\n');

    return {
      instructions,
      skills: composed.matchedSkills.map((s) => s.frontmatter.name),
    };
  }

  private buildPatientContextBlock(input: DraftPlanScriptInput): string {
    const cc = input.clinicalContext;
    const persona = input.personaHighlights.map((h) => `${h.label}:${h.description}`).join(' · ');
    return [
      '# 当前通话患者背景(真实数据,供你聊天时取用,不要编造、别照着推销)',
      `- 诊所:${input.clinicName} · 称呼:${input.patient.nameMasked} · 年龄:${input.patient.age ?? '未知'}`,
      persona ? `- 画像:${persona}` : '',
      `- 上次就诊发现 / 待处理:${cc.pendingTreatments.join('、') || input.plan.reasons[0]?.reason || '(无)'}`,
      `- 主治医生:${cc.primaryDoctorName ?? '(未知)'} · 距上次到店:${cc.daysSinceLastVisit ?? '未知'} 天`,
      cc.lastVisitSummary ? `- 上次到店:${cc.lastVisitSummary}` : '',
      cc.ongoingChains.length ? `- 在管治疗:${cc.ongoingChains.join(' / ')}` : '',
      `- 老客/新客:已完成 ${cc.completedTreatmentCount} 次治疗`,
    ]
      .filter(Boolean)
      .join('\n');
  }
}
