/**
 * 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);
const fmtDate = sharedFmtDate;

// ────────────────────────────────────────────────
// Patient
// ────────────────────────────────────────────────
export const mockPatient = {
  id: 'ptn_8f3c1a2b',
  externalId: '5i5ya_PA00284917',
  medicalRecordNumber: 'SH0Q011691' as string | null,
  brandId: null as string | null, // 品牌 GUID(EMR 跳转 {brandId} 用)
  dedicatedCs: { id: '5499', name: '姜莹' } as { id: string; name: string } | null,
  name: '张志远',
  nameMasked: '张志*',
  gender: '男',
  age: 42 as number | null, // null = 生日缺失,UI 显示 "?" 岁(跟列表页一致)
  birthDate: '1984-03-12',
  phone: '13855612937',
  phoneMasked: '138****2937',
  phoneVerified: false,
  tags: ['VIP 金卡', '老客户'] as string[],
  preferences: {
    contactWindow: '19:00–21:30',
    preferredChannel: ExecutionChannel.PHONE,
    language: '普通话',
  },
  profile: {
    doNotContact: false,
    deceased: false,
    ltv: 48200,
    firstVisit: '2022-06-08',
    lastVisit: fmtDate(daysAgo(38)),
    contacts: [
      {
        relationship: 'mother',
        relationshipLabel: '妈妈',
        name: '伍晴晴',
        phone: '13800000000',
        linked: true,
        isKin: true,
        age: 58,
        relatedPatientId: 'p-mock-mother',
        planId: null,
        externalId: '5i5ya_PA00999001',
        medicalRecordNumber: 'SH0Q099001',
      },
    ] as Array<{
      relationship: string;
      relationshipLabel: string;
      name: string | null;
      phone: string | null;
      linked: boolean;
      /** 是不是亲戚(KIN_RELATIONSHIPS 白名单;friend/other 不算)—— 只有亲戚进「关联客户」行 */
      isKin: boolean;
      age: number | null;
      relatedPatientId: string | null;
      /** 关系人在本 scope 内可打开的工单;null = 没有 → 只显示姓名,不给链接 */
      planId: string | null;
      /** 关系人宿主侧 id / 病历号 —— 填 VIEW_PATIENT 槽位占位 */
      externalId: string;
      medicalRecordNumber: string | null;
    }>,
    // ⚠️ TEST ONLY — 监护人(儿童/老人触达 fallback),真实手机号到位前仅演示
    guardian: {
      relationship: 'mother',
      relationshipLabel: '妈妈',
      name: '伍晴晴',
      phone: '13800000000',
    } as { relationship: string; relationshipLabel: string; name: string | null; phone: string | null } | null,
  },
};

// ────────────────────────────────────────────────
// 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;
  /// 最近一次诊断(re-trigger 证据)+ 该次医生真实医嘱(doctor_advice)
  latestDxAt?: string;
  latestDxName?: string;
  latestDxAdvice?: string;
  /// 生命周期提示("终身维护(永不闭环)" 等)— UI tooltip
  lifecycleNoteZh?: string;
  /// 诊断码(K00–K09)— 跨链对齐 reason↔chain 用(WhyCard 替代闭环抑制按 code+牙位对齐)
  code?: 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[];
  /// 结构化 payload(如 entitlement_status 的 {commercialInsured, commercialInsurers, medicalInsured...});多数特征为 null
  data?: unknown;
};

// mock 画像 —— 只用**在跑的**特征 key(与 PERSONA_FEATURE_SPECS 一致)。
// 原来这里摆着 value / treatment_chain_status / recall_risk / communication_preference /
// cooperation_attitude / doctor_relation 六个 —— 前三个 W7 已并入 rfm、后三个从未实现,
// 于是 mock 长期展示着系统根本不产出的标签,拿它当参照会看错。
export const mockPersona = {
  id: 'prsn_v7',
  version: 7,
  computedAt: daysAgo(2),
  refreshedAt: daysAgo(2),
  features: [
    {
      key: PersonaFeatureKey.URGENCY_LEVEL,
      label: '急迫等级',
      value: '紧急 · 末诊140天 · 2 类潜在治疗',
      tone: 'rose',
      evidence: ['fact_dx_2025_12', 'fact_visit_2026_04'],
      data: { level: 'urgent', levelZh: '紧急', lastVisitDays: 140, pendingTypes: 2 },
    },
    {
      key: PersonaFeatureKey.POTENTIAL_TREATMENT,
      label: '潜在治疗',
      value: '潜在种植 / 潜在修复',
      tone: 'amber',
      evidence: ['fact_dx_2025_12'],
      data: { types: ['implant', 'restoration'], labels: ['潜在种植', '潜在修复'] },
    },
    {
      key: PersonaFeatureKey.RFM,
      label: '价值分群',
      value: '重要价值 · 距上次 140 天 · 就诊20次 · 累计¥48,200',
      tone: 'indigo',
      evidence: ['fact_pay_2024_05', 'fact_pay_2024_07', 'fact_pay_2024_10'],
      data: { segment: 'important_value', recencyDays: 140, freqCount: 20, monetaryCents: 4820000 },
    },
    {
      key: PersonaFeatureKey.LIFECYCLE_STAGE,
      label: '生命周期',
      value: '成熟客 · 末诊140天 · 就诊20次',
      tone: 'brand',
      evidence: ['fact_visit_2026_04'],
      data: { stage: 'mature', label: '成熟客', recencyDays: 140, totalVisits: 20 },
    },
    {
      key: PersonaFeatureKey.TREATMENT_HISTORY,
      label: '治疗史',
      value: '种植史 / 牙周治疗史',
      tone: 'amber',
      evidence: ['fact_tx_2024_07'],
      data: { types: ['implant_history', 'perio_history'], labels: ['种植史', '牙周治疗史'] },
    },
    {
      key: PersonaFeatureKey.AGE_BRACKET,
      label: '年龄段',
      value: '中年 · 42岁',
      tone: 'sky',
      evidence: [],
      data: { bracket: 'middle_aged', label: '中年', ageYears: 42 },
    },
  ] 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[];
    focusCategory?: string | null;
    patientAge?: number | null;
  } | 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;
  }>;
  /// v3.0 三维算法 breakdown(详情页"为什么 X 分"渲染数据);旧 mock 数据可空
  breakdown?: {
    priority: {
      urgency: number;
      value: number;
      willingness: number;
      rfmAdherence: number;
      intentBehavior: number;
      trustBase: number;
      freshness: number;
      confidenceFactor: number;
      base: 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: '望京旗舰店',
  targetClinicId: null as string | null, // 原始诊所 id(EMR 跳转 {clinicId} 用)
  executorClinic: '望京旗舰店',
  goal: '邀约本周种植面诊,避免邻牙倾斜 / 对颌伸长' as string | null,
  assignee: { id: 'usr_csliu', name: '刘悦', role: UserRole.STAFF as UserRole },
  /// 认领人原始值(null = 无人认领)—— 认领闸判定用,见 adapt-data 同名字段注释
  assigneeUserId: 'usr_csliu' as string | null,
  assignedAt: NOW,
  recycleAt: new Date(NOW.getTime() + 4 * 3600_000) as Date | null,
  /// 召回冷静期 / 终态抑制窗到期时间(null=无抑制)— 头部"下次回访 / 已暂缓至 X"角标
  snoozedUntil: null as Date | null,
  /// 召回反馈(plan 级)— 标题栏拇指当前态 + 文字
  recallFeedback: null as 'up' | 'down' | null,
  recallFeedbackNote: null as string | null,
  updatedAt: NOW 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: `• 张先生您好,我是望京旗舰店的客服
• 李医生特意交代我来关注您的后续情况
• 自从去年12月检查后,您口腔情况怎么样?`,
    },
    {
      id: 'informMissed',
      label: '告知潜在治疗',
      durationHint: '1 分钟',
      markdown: `• 上次来检查的时候,李医生注意到您左下大牙有缺失牙的情况
• 缺牙的地方如果不处理,旁边的牙齿可能会慢慢歪掉,时间一长吃东西也不太舒服
• 趁现在牙槽骨条件还不错,早点处理效果更好
• 这个情况,李医生也特别嘱咐我们提醒您一下`,
    },
    {
      id: 'reviewAdvice',
      label: '复查建议',
      durationHint: '1 分钟',
      markdown: `• 如果方便的话,您看最近有没有时间来院复查一下
• 让李医生帮您再仔细看看
• 复查检查约30分钟,了解缺失牙位目前状况
• 李医生【时间段1】和【时间段2】这两个时间段有空,您看哪个时间比较方便?`,
    },
    {
      id: 'closing',
      label: '结束回访语',
      durationHint: '30 秒',
      markdown: `【预约成功】
• 好的,那我们【具体预约时间】见,祝您生活愉快
【预约不成功】
• 没关系,我下周再联系您,祝您生活愉快`,
    },
  ] as ScriptSection[],
};

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

export { NOW };
