#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""从三份文档提炼待办，写入 刘新元 的工作台待办（CloudBase todos 集合 + 数据/todos.json 双写）。

来源（2026-09-21 用户提供）：
  · 20260921大客户部周会纪要(2).xlsx  —— 9月W3 sheet（含 W3 下周工作计划 + 重点事项/改善建议）
  · 销售工程师周报-赵云浩（2026年9月W3).xlsx —— 二、下周工作计划
  · 销售工程师周报-刘子研（2026年9月20).xlsx —— 二、下周工作计划

规范（用户硬要求）：一条一个事项、落到具体 owner、分条分类。
"""
import json, io, os, random, string, subprocess, datetime, shutil

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
TODOS_JSON = os.path.join(ROOT, '数据/todos.json')
TCB = '/Users/liuxinyuan/.npm-global/lib/node_modules/@cloudbase/cli/dist/standalone/cli.js'
CB_ENV = 'bier-sales-d0gatbvlx288724e9'
USER = '刘新元'
DOC_ID = '65ccbb1a6a8b2a000004712c33006485'   # 云端 todos 文档 _id（已核实）
TODAY = '2026-09-21'

def nid():
    return 'mt' + ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(9))

# (text, cat, client, due, note)
ITEMS = [
 # ── 本周重点 / 改善建议（我牵头） ──
 ('【我·销售支持】货号规则规范：多组分产品未在货号体现组分数量、且有一物多码现象，立即按现有货号规则全面规范系统内物料信息（期间不另发新规则）',
  'other', '', '2026-09-26', '9月W3 周会改善建议1'),
 ('【研发/质量】搭建 16S/18S 与 NGS 的对标数据，用于 NA 类客诉处理时向客户展示，提升 NA 控制体系说服力',
  'complaint', '', '2026-10-15', '9月W3 周会改善建议2；圣湘尤其追问'),
 ('【研发+生产】评估搭建 mNGS 做 NA 控制方案（备货检测 NA 已消耗近 2 千 T 物料与人工，效率低于直接上 mNGS）',
  'complaint', '', '2026-10-15', '圣湘脓毒症项目诉求'),
 # ── 首要关注的大客户部质量问题（5 条） ──
 ('【赵云浩】万孚 FE20-50：客户本周测试 FE20-002902-30，目标做到与诺唯赞/艾科瑞一致，并支持 50U（后续还有机会把丢的项目拿回来）',
  'complaint', '广州万孚', '2026-09-27', '月销 5 万+；竞品艾科瑞/诺唯赞为 50U'),
 ('【赵云浩+生产】圣湘 FM2181-4-NA-020303（脓毒症转产备货）：上个月接单的研发采购仍发不出，必须给出可发货时间节点（暴露 NA 控制提前量不足）',
  'complaint', '湖南圣湘', '2026-09-25', '客户本周提中试采购'),
 ('【赵云浩】圣湘 FM2181-4-NA-095203 NA 控制：跟进我司破坏点阶段性结果后的客户污染测试反馈',
  'complaint', '湖南圣湘', '2026-09-26', '月销 20 万'),
 ('【赵云浩】圣湘 FE16-NA-50：污染源已锁定在抗体（粪肠球菌），复检结果出具后与客户对齐后续质检标准',
  'complaint', '湖南圣湘', '2026-09-26', '月销 5 万+'),
 ('【赵云浩】纳克冻干 RNA 客诉：客户已正式提出全额换货，走换货流程 + 输出调查报告',
  'complaint', '郑州纳克', '2026-09-26', '涉及十余万 T；我方冻干问题'),
 # ── 天隆 003006 客诉（重点） ──
 ('【刘子研】天隆 MD2104-003006-DB（LOT20260902，10 万人份）客诉：稳定客户情绪 + 我司初步结论出来后与刘小辉、张建开线上会',
  'complaint', '苏州天隆', '2026-09-25', '客户诉求=换货+调查报告+供货保障'),
 ('【刘子研】天隆 003006 批间差：跟进张建寄 A+C 体系（加合胞病毒引探）测试，并追踪刘小辉组已发终端客户的试剂反馈',
  'post', '苏州天隆', '2026-09-30', '需技术研发按既定进度提供实验数据'),
 ('【刘子研】天隆 刘小辉 PM202（0526 批次）复测验证结果跟进（该批每月出货海外 150 盒）',
  'complaint', '苏州天隆', '2026-09-30', ''),
 ('【刘子研】天隆食品安全（荧光素酶原料）：彭老师不了解该线，改找王新旺跟进',
  'custom', '苏州天隆', '2026-09-30', '新增需求'),
 # ── 丹威 ──
 ('【刘子研】丹威 Lamp 结核冻干优化：内部立项并推进，10 月中前输出第一版优化配方给客户测试（客户在泰国数十家医院推广，后续几十万人份）',
  'custom', '杭州丹威', '2026-10-23', '客户可提供引探/质粒/仪器'),
 ('【刘子研】丹威回款：敲定 9/30 前回款 4 万，23 号跟进进度',
  'other', '杭州丹威', '2026-09-30', '回款'),
 ('【刘子研】丹威 FM2181-4 收货换货：客户三次未退回，落实准确退回时间',
  'post', '杭州丹威', '2026-09-25', ''),
 # ── 迪安 ──
 ('【刘子研+我】迪安：内部准备新版宣讲 PPT，争取约见轮值总裁施玉鹏（结核线为主，向 CDC/海外非医保扩展）',
  'meeting', '杭州迪安', '2026-09-30', '10 月开始谈次年预算'),
 ('【刘子研】迪安 王博结核项目：马来西亚药厂终端计划 600 万人份，10 月再次跟进项目进度并提前备货',
  'post', '杭州迪安', '2026-10-15', ''),
 # ── 复星 ──
 ('【刘子研+研发】复星 管慧慧 STD 项目：跟进 FMD0104-074901 液体测试效果；提供 FE20/FE40 最适配方范围；安排 0181-4+0104 冻干验证排查工艺差异',
  'post', '上海复星', '2026-09-30', '竞品菲鹏；真实样本耐抑制性差'),
 ('【刘子研】复星：给管慧慧寄 SNP、结核 lamp、快速 PCR 测试装；跟进王冰洁 STD V3 批间差监测方案（10 月评审）',
  'post', '上海复星', '2026-10-20', ''),
 # ── 其他客户 ──
 ('【刘子研+研发】佰奥莱博：评估 FM2181-4-020303、FMD5104-014429 在 pH11 裂解液下耐抑制性是否真不如 FM507（偏酸/中性/强碱三组比对）',
  'custom', '佰奥莱博', '2026-09-30', '粪便直扩项目'),
 ('【刘子研】新产业：周二下午拜访刘振华总（流水线 R8 / 片段化酶+假病毒保存液 / 数字 PCR / HIV 非特异问题）',
  'meeting', '新产业', '2026-09-22', '已预约'),
 ('【刘子研】丽珠：跟进吴燕 HBV 项目组、欧格 HIV 项目组进度，以及 BTE-8 耗材沉淀问题的客户影响与处理方案',
  'post', '丽珠试剂', '2026-09-30', ''),
 ('【赵云浩】圣湘公卫：4℃ 一个月数据本月必须拿到；16S/18S 监测工作计划落地；与客户对齐质量协议签订节点',
  'complaint', '湖南圣湘', '2026-09-30', '客户非常介意测序/NGS 手段'),
 ('【赵云浩】圣湘脓毒症中试：客户预计提 3 批（每批≥300ml），严格按客户要求控制污染，周一确认实验方案与物料',
  'complaint', '湖南圣湘', '2026-09-26', '内部方向不清晰，需加大投入'),
 ('【赵云浩】明日达：跟进 FMD0104-000829-5P / FMD0104-074901-5P 去 RT 酶测试结果，并安排 MD2104-092401 可冻干版本',
  'post', '北京明日达', '2026-09-30', 'DNA 快速冻干需求'),
 ('【赵云浩】郑州安图：E10-000725 采购订单（约 100ml）价格拉扯 + 通知内部先备物料',
  'post', '郑州安图', '2026-09-30', '客户近期下单'),
 ('【赵云浩】郑州中道回款：本月未收到新回款安排（剩余约 2.7 万），持续跟进',
  'other', '郑州中道', '2026-09-30', '回款'),
 ('【赵云浩】武汉明德 FMD5104-000829 / AS312-000901-T2 人源 RnaseP 污染客诉：内部排查验证 + 新订单备注控人源 RNaseP',
  'complaint', '武汉明德', '2026-09-30', ''),
 ('【赵云浩+财务】回款跟进：明德、圣湘、中道、纳克',
  'other', '', '2026-09-30', '回款'),
 # ── 部门/流程类（刘子研反馈的支持需求） ──
 ('【我·协调技术】需要技术部门整理「转产与未转产产品」清单，供销售一线对客使用',
  'other', '', '2026-09-30', '刘子研周报反馈1'),
 ('【我·协调生产/研发】需要生产及研发部门设置安全库存，避免客户急单/客诉期断供',
  'other', '', '2026-09-30', '刘子研周报反馈2'),
]


def build():
    items = []
    for text, cat, client, due, note in ITEMS:
        items.append({'id': nid(), 'text': text, 'done': False, 'cat': cat,
                      'client': client, 'due': due, 'note': note, 'created': TODAY})
    return items


def main():
    new_items = build()
    print('  待写入 %d 条（全部 done=false，created=%s）' % (len(new_items), TODAY))

    # ── ① CloudBase: 取回现有 → 追加 → UPDATE ──
    cmd = [{"TableName": "todos", "CommandType": "FIND",
            "Command": json.dumps({"find": "todos", "filter": {"user": USER}, "limit": 1})}]
    r = subprocess.run(['node', TCB, 'db', 'nosql', 'execute', '--command', json.dumps(cmd, ensure_ascii=False),
                        '--json', '-e', CB_ENV], capture_output=True, text=True, timeout=90)
    raw = r.stdout or ''
    s = raw.find('{')
    if s < 0:
        raise SystemExit('  ❌ 云端读取失败: %s' % (r.stderr or raw)[:500])
    _d = json.loads(raw[s:])
    if 'data' not in _d:
        raise SystemExit('  ❌ 云端返回异常: %s' % json.dumps(_d, ensure_ascii=False)[:400])
    doc = _d['data']['results'][0][0]
    old = doc.get('todos') or []
    print('  云端现有 %d 条 → 追加后 %d 条' % (len(old), len(old) + len(new_items)))
    merged = old + new_items

    upd = [{"TableName": "todos", "CommandType": "UPDATE",
            "Command": json.dumps({"update": "todos",
                                   "updates": [{"q": {"user": USER},
                                                "u": {"$set": {"todos": merged,
                                                               "updated": datetime.datetime.now().isoformat(timespec='seconds')}}}]})}]
    r2 = subprocess.run(['node', TCB, 'db', 'nosql', 'execute', '--command', json.dumps(upd, ensure_ascii=False),
                         '--json', '-e', CB_ENV], capture_output=True, text=True, timeout=90)
    raw2 = r2.stdout or ''
    s2 = raw2.find('{')
    ok_cb = False
    if s2 >= 0:
        d2 = json.loads(raw2[s2:])
        err = d2.get('error')
        if err:
            print('  ❌ 云端写入出错: %s' % json.dumps(err, ensure_ascii=False)[:300])
        else:
            try:
                res = ((d2.get('data', {}).get('results') or [[]])[0] or [{}])[0]
                n = res.get('n') or res.get('nModified') or res.get('nMatched')
                if isinstance(n, dict):
                    n = n.get('$numberInt') or n.get('$numberLong')
                ok_cb = n is None or int(n) > 0
                print('  云端 UPDATE 命中 n=%s → %s' % (n, '✅' if ok_cb else '❌'))
            except Exception:
                ok_cb = True
    if not ok_cb:
        print('  ⚠️ 云端写入未确认：%s' % (r2.stderr or raw2)[:200])

    # ── ② 本地 todos.json 同步（同一批 id） ──
    shutil.copy(TODOS_JSON, TODOS_JSON + '.bak_before_meeting_todos_20260921')
    local = json.load(io.open(TODOS_JSON, encoding='utf-8'))
    local.setdefault('users', {})
    local['users'][USER] = (local['users'].get(USER) or []) + new_items
    local['updated_at'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    io.open(TODOS_JSON, 'w', encoding='utf-8').write(json.dumps(local, ensure_ascii=False, indent=2))
    print('  本地 todos.json: %s → %d 条' % (USER, len(local['users'][USER])))

    # ── ③ 回读校验 ──
    cmd3 = [{"TableName": "todos", "CommandType": "FIND",
             "Command": json.dumps({"find": "todos", "filter": {"user": USER}, "limit": 1})}]
    r3 = subprocess.run(['node', TCB, 'db', 'nosql', 'execute', '--command', json.dumps(cmd3, ensure_ascii=False),
                         '--json', '-e', CB_ENV], capture_output=True, text=True, timeout=90)
    raw3 = r3.stdout or ''
    s3 = raw3.find('{')
    doc3 = json.loads(raw3[s3:])['data']['results'][0][0]
    cb_ids = {t['id'] for t in (doc3.get('todos') or [])}
    new_ids = {t['id'] for t in new_items}
    print('  回读云端: %d 条 ｜ 新条目命中 %d/%d %s' % (
        len(doc3.get('todos') or []), len(cb_ids & new_ids), len(new_ids),
        '✅' if new_ids <= cb_ids else '❌'))
    loc_ids = {t['id'] for t in json.load(io.open(TODOS_JSON, encoding='utf-8'))['users'][USER]}
    print('  回读本地: 新条目命中 %d/%d %s' % (len(loc_ids & new_ids), len(new_ids),
        '✅' if new_ids <= loc_ids else '❌'))
    print('  未关闭条数（云端）:', sum(1 for t in doc3.get('todos') or [] if not t.get('done')))


main()
