/**
 * Plan Detail 演示 mock 数据
 * 场景: treatment_initiation_recall(启治召回 / 漏治新链)
 * 业务约束:枚举值跟系统对齐(@pac/types ExecutionOutcome / ExecutionChannel / PersonaFeatureKey / PlanScenario)
 * AI 产物(script / summaries / persona)= 假数据,后续接 Vercel AI SDK 真实生成
 */

import {
  ExecutionChannel,
  PersonaFeatureKey,
  PlanScenario,
  UserRole,
} from '@pac/types';

import { fmtRel as sharedFmtRel, fmtDate as sharedFmtDate } from '@pac/utils/format';

const NOW = new Date('2026-05-15T10:24:00+08:00');
const daysAgo = (n: number) => {
  const d = new Date(NOW);
  d.setDate(d.getDate() - n);
  return d;
};
const hoursAgo = (n: number) => new Date(NOW.getTime() - n * 3600_000);

export const fmtRel = (d: Date): string => sharedFmtRel(d, NOW);
export const fmtDate = sharedFmtDate;

// ────────────────────────────────────────────────
// Patient
// ────────────────────────────────────────────────
export const mockPatient = {
  id: 'ptn_8f3c1a2b',
  externalId: '5i5ya_PA00284917',
  name: '张志远',
  nameMasked: '张志*',
  gender: '男',
  age: 42,
  birthDate: '1984-03-12',
  phone: '13855612937',
  phoneMasked: '138****2937',
  tags: ['VIP 金卡', '老客户'] as string[],
  preferences: {
    contactWindow: '19:00–21:30',
    preferredChannel: ExecutionChannel.PHONE,
    language: '普通话',
  },
  profile: {
    doNotContact: false,
    deceased: false,
    primaryContactType: '本人' as string | null,
    ltv: 48200,
    firstVisit: '2022-06-08',
    lastVisit: fmtDate(daysAgo(38)),
  },
};

// ────────────────────────────────────────────────
// Treatment Chains(治疗链 5 阶段,锚定 pac-goal-alignment §0)
// ────────────────────────────────────────────────
/// 5 阶段节点结构(W3 末重塑,跟后端 chain-composer ChainNode 同源)
///   每节点最多 4 信息位 + 视觉状态:
///     - title    : 具体动作(如 慢性牙周炎 / *全口洁治 / 牙周刮治术)
///     - detail   : 关键事实(如 全口 26 牙 / 1/3 步骤 / ¥58)
///     - doctor   : 主治 / 计划 医生名
///     - at       : 日期 YYYY.MM.DD
///     - hint     : discovered/entered/未闭环 显示的"建议下一步" 友好提示
///   label/note 保留兼容(旧前端调用)— 优先用 title/detail/doctor/hint
export type ChainNode = {
  stage: 1 | 2 | 3 | 4 | 5;
  title?: string;
  detail?: string;
  doctor?: string;
  at: string;
  hint?: string;
  done?: boolean;
  current?: boolean;
  missing?: boolean;
  /// 兼容旧字段(逐步淘汰)
  label?: string;
  note?: string;
};

/// 5 阶段链状态(W3 末从 3 态升级,跟后端 chain-composer 同源)
///   - discovered: 仅 S1 命中(诊断/推荐)— 召回算法关注的"潜在新链"
///   - entered:   S2 命中(已挂号/预约/付款但未真正治疗)
///   - ongoing:   S3 或 S4 命中(治疗中 / 复查中)
///   - closed:    S5 全条件满足 — 真正闭环(lifelong_maintenance 类永不到此)
export type ChainStatus = 'discovered' | 'entered' | 'ongoing' | 'closed';

export type Chain = {
  id: string;
  name: string;
  category: string;
  status: ChainStatus;
  currentStage: 1 | 2 | 3 | 4 | 5;
  value?: number;
  estimatedValue?: number;
  recurring?: boolean;
  target?: boolean;
  diagnosedAt?: string;
  gapDays?: number;
  /// 生命周期提示("终身维护(永不闭环)" 等)— UI tooltip
  lifecycleNoteZh?: string;
  /// 桶牙位(cross-chain alternative-closed 判定用,UI 不直接展示)
  toothPosition?: string;
  /// "替代治疗已覆盖"原因 chain.name(K04 后续 K08+种植覆盖等)
  alternativeClosedBy?: string;
  nodes: ChainNode[];
};

export const mockChains: Chain[] = [
  {
    id: 'chain_rest_2024',
    name: '单颗修复 · 26 号牙',
    category: 'restoration',
    status: 'closed',
    currentStage: 5,
    value: 4800,
    nodes: [
      { stage: 1, label: 'X 光发现龋损', at: '2024.05', note: 'CBCT + EMR', done: true },
      { stage: 2, label: '治疗计划 + 缴费', at: '2024.05', done: true },
      { stage: 3, label: '嵌体备牙 + 修复', at: '2024.06', done: true },
      { stage: 4, label: '复诊 1 周 / 1 月', at: '2024.07', done: true },
      { stage: 5, label: '闭环', at: '2024.08', done: true },
    ],
  },
  {
    id: 'chain_perio_2024',
    name: '牙周维护',
    category: 'periodontal',
    status: 'ongoing',
    currentStage: 4,
    value: 12600,
    recurring: true,
    nodes: [
      { stage: 1, label: '牙周检查', at: '2024.03', done: true },
      { stage: 2, label: 'SRP 计划 + 缴费', at: '2024.04', done: true },
      { stage: 3, label: '牙周基础 4 象限', at: '2024.05–07', done: true },
      {
        stage: 4,
        label: '季度维护(进行中)',
        at: '2024.10 至今',
        current: true,
        note: '下次预约 2026.07',
      },
      { stage: 5, label: '闭环', at: '—', missing: true },
    ],
  },
  {
    id: 'chain_implant_NEW',
    name: '种植修复 · 36 号牙',
    category: 'implant',
    status: 'discovered',
    currentStage: 1,
    target: true,
    estimatedValue: 22000,
    diagnosedAt: '2025.12.10',
    gapDays: 156,
    nodes: [
      { stage: 1, label: 'CBCT 诊断 K08.1 牙缺失', at: '2025.12', note: '建议种植', done: true },
      { stage: 2, label: '未进入', at: '—', missing: true },
      { stage: 3, label: '未进入', at: '—', missing: true },
      { stage: 4, label: '未进入', at: '—', missing: true },
      { stage: 5, label: '未进入', at: '—', missing: true },
    ],
  },
];

// ────────────────────────────────────────────────
// Persona(系统 4 起步 features + 2 扩展)
// ────────────────────────────────────────────────
export type PersonaFeature = {
  key: string;
  label: string;
  value: string;
  tone: string;
  evidence: string[];
};

export const mockPersona = {
  id: 'prsn_v7',
  version: 7,
  computedAt: daysAgo(2),
  features: [
    {
      key: PersonaFeatureKey.VALUE,
      label: '患者价值',
      value: 'VIP 金卡 · LTV ¥48,200',
      tone: 'indigo',
      evidence: ['fact_pay_2024_05', 'fact_pay_2024_07', 'fact_pay_2024_10'],
    },
    {
      key: PersonaFeatureKey.TREATMENT_CHAIN_STATUS,
      label: '治疗链状态',
      value: '2 条闭环/在管 · 1 条断口',
      tone: 'amber',
      evidence: ['fact_dx_2025_12', 'fact_tx_2024_07'],
    },
    {
      key: PersonaFeatureKey.RECALL_RISK,
      label: '流失风险',
      value: '低 — 牙周维护按期',
      tone: 'emerald',
      evidence: ['fact_visit_2026_04'],
    },
    {
      key: PersonaFeatureKey.COMMUNICATION_PREFERENCE,
      label: '沟通偏好',
      value: '电话 · 工作日 19:00 后',
      tone: 'sky',
      evidence: ['fact_pref_2024'],
    },
    {
      key: PersonaFeatureKey.COOPERATION_ATTITUDE,
      label: '配合态度',
      value: '高 · 6 次复诊全到',
      tone: 'emerald',
      evidence: ['fact_visit_history'],
    },
    {
      key: PersonaFeatureKey.DOCTOR_RELATION,
      label: '主治医患',
      value: '李医生(种植)· 王医生(牙周)',
      tone: 'slate',
      evidence: ['fact_emr_2024'],
    },
  ] as PersonaFeature[],
};

// ────────────────────────────────────────────────
// FollowupPlan + PlanReason
// ────────────────────────────────────────────────
export type PlanReason = {
  id: string;
  scenario: string;
  /// 子规则 key(missing_tooth / perio_no_srp / endo_no_rct …)— W3 末 plan_reasons 拆细后每行带
  subKey?: string | null;
  /// W3 末:结构化召回信号(DB 存 raw enum,前端字典翻译富文本)
  signals?: {
    subKey: string;
    triggers: Array<{ type: string; code?: string | null }>;
    toothPosition?: string | null;
    daysSince: number;
    expectedCategories: string[];
  } | null;
  scenarioLabel: string;
  priorityScore: number;
  lifecycle: 'one_shot' | 'recurring';
  source: 'algorithm' | 'manual' | 'campaign' | 'rule';
  reason: string;
  evidence: Array<{
    id: string;
    label: string;
    source: string;
    occurredAt: string;
    negative?: boolean;
  }>;
  /// v2.1 6 因子算法 breakdown(详情页"为什么 X 分"渲染数据);旧 mock 数据可空
  breakdown?: {
    priority: {
      clinicalBase: number;
      timeWindowFactor: number;
      main: number;
      valueBonus: number;
      likelihoodBonus: number;
      urgencyBonus: number;
      confidenceFactor: number;
      raw: number;
    };
    subKey: string | null;
    mergedSubKeys?: string[];
  } | null;
};

export const mockPlan = {
  id: 'pln_2026_05_15_zhangzhiyuan',
  version: 3,
  status: 'assigned' as string,
  priorityScore: 92,
  contactAttempts: 0,
  maxContactAttempts: 4,
  targetClinic: '望京旗舰店',
  executorClinic: '望京旗舰店',
  goal: '邀约本周种植面诊,避免邻牙倾斜 / 对颌伸长' as string | null,
  assignee: { id: 'usr_csliu', name: '刘悦', role: UserRole.STAFF as UserRole },
  assignedAt: NOW,
  recycleAt: new Date(NOW.getTime() + 4 * 3600_000) as Date | null,
  recommendedAt: NOW,
  recommendedRole: UserRole.STAFF as UserRole,
  recommendedChannel: ExecutionChannel.PHONE as ExecutionChannel,
  reasons: [
    {
      id: 'rsn_1',
      scenario: PlanScenario.TREATMENT_INITIATION_RECALL,
      scenarioLabel: '启治召回',
      priorityScore: 92,
      lifecycle: 'one_shot',
      source: 'algorithm',
      reason:
        '患者于 2025-12-10 CBCT 检查发现 36 牙缺失,医生 EMR 诊断 K08.1 并建议种植,至今 156 天未启动种植治疗(无预约/无缴费/无治疗计划)。期间正常完成 2 次牙周维护复诊,触达可行性高。',
      evidence: [
        {
          id: 'fact_dx_2025_12',
          label: 'EMR 诊断: K08.1 牙缺失 · 36',
          source: 'encounter_record',
          occurredAt: '2025-12-10',
        },
        {
          id: 'fact_img_2025_12',
          label: 'CBCT 影像 · 36 区骨量评估',
          source: 'image_record',
          occurredAt: '2025-12-10',
        },
        {
          id: 'fact_advice_2025_12',
          label: '医嘱: 建议 6 个月内种植',
          source: 'encounter_record',
          occurredAt: '2025-12-10',
        },
        {
          id: 'fact_neg_implant',
          label: '无 implant 类 treatment fact',
          source: 'fact_query',
          occurredAt: '—',
          negative: true,
        },
      ],
    } as PlanReason,
  ],
};

// ────────────────────────────────────────────────
// Plan Summaries(AI 生成 — 假数据,后续接 Vercel AI SDK)
// ────────────────────────────────────────────────
export const mockSummaries = {
  one_page: {
    type: 'one_page',
    status: 'ready' as const,
    source: 'agent' as const,
    generatedAt: hoursAgo(2),
  },
  medical_record: {
    type: 'medical_record',
    status: 'ready' as const,
    source: 'agent' as const,
    generatedAt: hoursAgo(2),
    content: `**主诉摘要**
2025-12-10 因左下后牙咀嚼无力就诊,CBCT 显示 36 牙缺失(已脱落约 8 月),36 区牙槽嵴形态良好,垂直骨高度 11.2mm,可种植。

**诊断**
- K08.1 牙缺失(36)
- K05.30 慢性牙周炎(全口,在管)

**医嘱**
建议 6 个月内行 36 区种植修复;同时维持现有牙周维护周期(季度)。

**既往**
- 2024.06 完成 26 嵌体修复(单颗)— 已闭环
- 2024.04 起牙周基础治疗 + 季度维护(在管,下次 2026.07)
- 无烟酒史,无种植禁忌`,
  },
  treatment_chain: {
    type: 'treatment_chain',
    status: 'ready' as const,
    source: 'agent' as const,
    generatedAt: hoursAgo(2),
    content: `患者共 3 条治疗链:

**① 单颗修复链(26 号嵌体)** — ✅ 已闭环
2024.05 X 光发现龋损 → 2024.05 计划缴费 → 2024.06 备牙修复 → 2024.07 复诊 → 2024.08 闭环。

**② 牙周维护链** — 🟡 进行中(在管)
2024.03 牙周检查 → 2024.04 SRP 计划 → 2024.05–07 基础治疗(4 象限) → 2024.10 起季度维护,下次预约 2026.07。患者依从性高,6 次复诊全到。

**③ 种植修复链(36 号)** — ⛔️ 未启动(本次召回目标)
2025.12.10 CBCT + EMR 诊断牙缺失 + 医嘱种植 → 后续 0 动作(无计划/无缴费/无预约/无治疗)。已 156 天。`,
  },
};

// ────────────────────────────────────────────────
// Plan Script(AI 生成 — 假数据)
// ────────────────────────────────────────────────
export type ScriptSection = {
  id: string;
  label: string;
  durationHint: string;
  markdown: string;
};

export const mockScript = {
  status: 'ready' as const,
  source: 'agent' as const,
  generatedAt: hoursAgo(2),
  sections: [
    {
      id: 'opening',
      label: '开场',
      durationHint: '30 秒',
      markdown: `**目的**:亲切自然地建立通话,以"牙周维护回访"作为切入,避免一上来就推销。

> "您好,请问是张先生吗?我是望京旗舰店的客服小刘。今天给您打电话,一是您下次牙周维护快到了(7 月),想跟您提前确认时间;二是看到 12 月份李医生给您拍过 CBCT,有点情况想跟您同步一下,您现在方便聊几分钟吗?"

**注意**
- 称呼用"张先生",不用全名
- 工作日 19:00 后是患者偏好窗口`,
    },
    {
      id: 'followup',
      label: '切入话题',
      durationHint: '1–2 分钟',
      markdown: `**目的**:把 5 个月前的诊断结论,自然回到"该启动了"。

> "上次您拍的 CBCT,李医生看了片子,左下 36 那颗缺了挺久了,旁边的牙有点往那边倒。如果再拖,后面想种植可能需要先做正畸或者补骨,流程更长成本更高。"

> "李医生当时建议 6 个月内安排种植,现在差不多到时间了。我们想约您本周来做个种植面诊,**这次只是评估和确认方案,不做任何操作,大概 30 分钟**,您看周几方便?"

**异议预判**
- "再等等" → 强调时间窗(再拖可能需正畸/补骨)
- "费用高" → 引导先面诊,方案出来后再算费用
- "在外院看过" → 提交「已在外院治疗」并关闭本次召回`,
    },
    {
      id: 'objection',
      label: '异议处理',
      durationHint: '按需',
      markdown: `### A. "我再考虑考虑"
> "完全理解,种植是个大决定。这样,我先帮您把李医生的面诊时间留出来,**周四晚上 7 点或者周六上午**,您选一个?到现场看了方案再决定也不晚。"

### B. "价格太贵"
> "种植的具体价格要看骨量和品牌,李医生面诊后会给您 2-3 个方案,从经济款到进口品牌都有。您先来评估,价格不合适咱们再聊别的修复方式,比如桥体。"

### C. "我牙周还在维护,等做完再说"
> "牙周维护和种植不冲突的,种植反而需要牙周稳定才能做,您现在正好是窗口期。"

### D. "已经在别的医院看了"
> "好的张先生,那我这边帮您把这条记录关一下,您牙周这块还是按原来的周期回来就行,**祝您一切顺利**。"
> → 提交结果选「已在外院治疗」`,
    },
    {
      id: 'close',
      label: '结束 · 信息确认',
      durationHint: '30 秒',
      markdown: `> "好的张先生,那我帮您约 **周四(5/21)晚 7:00 李医生**,到时候提前 10 分钟到前台就行。我会给您发个企微提醒,您注意接收。还有别的需要么?"

**回写要点**
- 成功约上面诊 → 提交结果选「成功转化为新预约」,填预约时间 + 医生
- 同意但未定日期 → 选「约定下次回访」,填预计时间
- 考虑中 → 选「考虑中近期再跟进」,7 天后系统提醒二次跟进`,
    },
  ] as ScriptSection[],
};

// ────────────────────────────────────────────────
// Outcome 枚举 — 已迁移到 @pac/types EXECUTION_OUTCOME_META(单一真理源)
// outcome-form.tsx 直接从 types 拉,前后端共享 label / tone / drivesStatus
// 这里不再维护;改 outcome 改 packages/types/src/enums/index.ts
// ────────────────────────────────────────────────

export { NOW };
