import { Injectable } from '@nestjs/common';
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import type { AiCall } from '../../ai-call.interface';
import type { ScriptContext } from '../draft-plan-script/shared/input.types';
import { composeSystem } from '../draft-plan-script/shared/skill-composer';
import { DraftPlanScriptSkillRegistry } from '../draft-plan-script/shared/skill-registry.service';
import { WecomWriteSchema, type WecomWriteZ } from './schema';
import { buildWecomWritePrompt } from './prompts';

/**
 * 企微话术的**唯一** AiCall(2026-08 从 plan → write → verify 三步砍成一步,见 wecom.strategy 文件头)。
 *
 * ═══ 与电话档共用了什么、没共用什么 ═══════════════════════════
 * 共用(直接 import,⛔ 不复制):
 *   · ScriptContext 输入契约、`buildRichFactBlock` 患者事实块(谁、哪颗牙、医生说了什么)
 *   · 安全护栏 `forbiddenWordsBlock` / 福利硬约束 / 自报家门占位 / 医生姓脱敏
 *   · 人群 skills(成人/儿童共性)与 `composeSystem` 装配逻辑
 *   —— 这些都跟"用电话还是企微说"无关。复制一份的代价是护栏有两处,
 *      改了一处另一处会悄悄留在旧版本,而漏了哪条要等客服**已经发给患者**才发现。
 * 没共用(本目录自己写):
 *   · 输出 schema:电话 `sections[]`(伴飞逐段高亮要它)→ 企微单块 `markdown`
 *   · format.md:电话是口语/分段/口头二选一 → 企微是书面/断行/可复制即发
 *   · verify 多一条⑤「可直接发送」(无小标题、无占位残留、无给客服看的话)
 *
 * ⚠️ 企微**只有深度档**(产品定):它是一条发出去就收不回的消息,
 *   没有"边打边看着调整"的机会,所以不给低质量档。
 */

/**
 * 本目录自己的输出格式(覆盖 tier 默认的那份)。
 *
 * ⛔ **不能用 `__dirname`**(踩过:ENOENT)—— SWC dev 的产物在 `dist/src/...`、
 *   tsc prod 在 `dist/...`,同一个 `__dirname` 在两态下指向不同层级。
 *   照抄 `resolveScriptRoot` 那套 env → src → dist 的策略(理由见它的文件头注释):
 *   `cwd` 在 dev/prod 都是 apps/pac-service 根,才是稳的。
 */
function wecomFormatPath(): string {
  const rel = 'modules/ai/calls/draft-wecom-script/skills/_base/format.md';
  const src = join(process.cwd(), 'src', rel);
  return existsSync(src) ? src : join(process.cwd(), 'dist', rel);
}

/** ⚠️ 只剩 ctx —— 规划(plan)与修订(repairIssues)两条 2026-08 一起砍了,见 wecom.strategy 文件头 */
export interface WecomWriteInput {
  ctx: ScriptContext;
}

@Injectable()
export class WecomWriteCall implements AiCall<WecomWriteInput, WecomWriteZ> {
  readonly kind = 'script' as const;
  readonly callKey = 'draft_wecom_script_write';
  // ⚠️ 换 promptVersion 会让缓存整体失效(这是想要的):流程和形态都变了,旧缓存不该再命中
  readonly promptVersion = 'draft_wecom_script@2026-08-05-single-v2';
  readonly defaultModelId = 'deepseek-v4-flash';
  readonly outputSchema = WecomWriteSchema;
  constructor(private readonly skillRegistry: DraftPlanScriptSkillRegistry) {}
  buildPrompt(input: WecomWriteInput) {
    // tier 传 'deep' 只为**挑 skill**(人群共性 / 深度档知识,与渠道无关);
    // 输出形态靠第 4 个参数换成企微那份 format.md。见 composeSystem 的注释。
    const composed = composeSystem(
      input.ctx,
      this.skillRegistry.getAllSkills(),
      'deep',
      wecomFormatPath(),
      false, // ⛔ 企微不留【时间段】占位(整段复制直发,占位会原样发给患者)
    );
    return { system: composed.systemPrompt, prompt: buildWecomWritePrompt(input) };
  }
}
