#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成《测试报告定向收集 · 演示版》——自包含 HTML，不依赖后端/登录。

原理：取正式版页面 + 把 schema/订单/货号 内联进页面，AI 整理改为"优先调接口、失败则本地生成"。
用法: python3 脚本/build_demo_page.py
"""
import json, os, re, sys

ROOT = os.path.expanduser('~/Desktop/Hermes输出-工作类')
SRC = os.path.join(ROOT, '工具/测试报告定向收集.html')
OUT = os.path.join(ROOT, '工具/测试报告定向收集_演示版.html')

src = open(SRC, encoding='utf-8').read()

# ── 1) 备好内联数据（精简字段，控制体积）────────────────────
schema = json.load(open(os.path.join(ROOT, '数据/test_report_schema.json'), encoding='utf-8'))

orders = []
try:
    raw = json.load(open(os.path.join(ROOT, '数据/mcp_orders_input.json'), encoding='utf-8'))
except Exception:
    raw = []
try:
    spmap = (json.load(open(os.path.join(ROOT, '数据/order_sp_map.json'), encoding='utf-8')) or {}).get('map') or {}
except Exception:
    spmap = {}
seen = set()
for o in (raw if isinstance(raw, list) else []):
    no = str(o.get('单据编号') or '').strip()
    if not no or no in seen:
        continue
    seen.add(no)
    orders.append({
        'no': no,
        'customer': str(o.get('销售订单关联客户') or o.get('购货单位#') or '').strip(),
        'date': str(o.get('创建时间') or '')[:10],
        'sp': spmap.get(no) or str(o.get('创建者') or '').strip(),
        'dept': str(o.get('销售部门') or '').strip(),
    })
orders.sort(key=lambda x: x['date'], reverse=True)

skus = []
try:
    pm = json.load(open(os.path.join(ROOT, '数据/product_master.json'), encoding='utf-8'))
    for s in (pm.get('skus') or []):
        skus.append({'sku': s.get('sku', ''), 'name': s.get('name', ''),
                     'spec': s.get('spec', ''), 'line': s.get('line', ''), 'cat': s.get('cat', '')})
except Exception:
    pass

demo = {'schema': schema, 'orders': orders, 'skus': skus, 'mockAI': 1}

# ── 2) 注入内联数据 ──────────────────────────────────────────
inject = ('<script>\n/* ===== 演示版内联数据（生成于 build_demo_page.py）：'
          'schema %d 方向 / 订单 %d 笔 / 货号 %d 个 ===== */\n'
          'window.__DEMO__ = %s;\n</script>\n' %
          (len(schema.get('products', [])), len(orders), len(skus),
           json.dumps(demo, ensure_ascii=False, separators=(',', ':'))))
src = src.replace('<script>\n/* ══════════ 基础配置 ══════════ */', inject + '<script>\n/* ══════════ 基础配置 ══════════ */', 1)

# ── 3) loadSchema / loadOptions 走内联数据 ───────────────────
src = src.replace(
    "function loadSchema() {\n  apiCall('/api/test-report/schema')",
    "function loadSchema() {\n"
    "  if (window.__DEMO__) {  /* 演示版：直接用内联 schema */\n"
    "    SCHEMA = window.__DEMO__.schema || {}; PRODUCTS = SCHEMA.products || [];\n"
    "    $('prodCount').textContent = PRODUCTS.length + ' 个方向 · 演示版';\n"
    "    renderProducts(); return;\n"
    "  }\n"
    "  apiCall('/api/test-report/schema')", 1)

src = src.replace(
    "function loadOptions() {\n  apiCall('/api/test-report/options')",
    "function loadOptions() {\n"
    "  if (window.__DEMO__) {  /* 演示版：用内联订单/货号 */\n"
    "    ORDERS = window.__DEMO__.orders || []; SKUS = window.__DEMO__.skus || [];\n"
    "    $('orderMeta').textContent = '（演示数据）已载入 ' + ORDERS.length + ' 笔订单 · ' + SKUS.length + ' 个货号';\n"
    "    return;\n"
    "  }\n"
    "  apiCall('/api/test-report/options')", 1)

# ── 4) AI 整理：演示版用本地生成（不调接口）──────────────────
local_md = r"""
/* ===== 演示版：本地生成结构化 Markdown（不联网） ===== */
function localStructureMD(p) {
  var L = [];
  var title = (p.product || '未选方向') + (p.customer ? ' · ' + p.customer : '');
  L.push('# ' + title);
  L.push('');
  L.push('## 一、基本信息');
  L.push('');
  L.push('| 项目 | 内容 |');
  L.push('| --- | --- |');
  [['产品方向', p.product], ['产品类型', p.product_type], ['订单号', p.order_no],
   ['客户', p.customer], ['货号', (p.sku || '') + (p.sku_name ? ' ' + p.sku_name : '')],
   ['负责销售', p.sales], ['测试时间', p.test_date]].forEach(function (kv) {
    L.push('| ' + kv[0] + ' | ' + (kv[1] || '未提供') + ' |');
  });
  if ((p.images || []).length) L.push('| 上传附件 | ' + p.images.length + ' 个：' + p.images.map(function (i) { return i.name || ''; }).join('、') + ' |');
  L.push('');
  var ratings = [];
  (p.sections || []).forEach(function (sec, si) {
    // 第一段「基本信息」已由上面的表格呈现，跳过避免重复（2026-09-16 修复）
    if (si === 0 && sec.title.indexOf('基本信息') >= 0) return;
    L.push('## ' + sec.title);
    L.push('');
    var fields = (sec.fields || []).filter(function (f) { return String(f.value || '').trim(); });
    if (!fields.length) { L.push('未提供'); L.push(''); return; }
    L.push('| 指标 | 填写值 |');
    L.push('| --- | --- |');
    fields.forEach(function (f) {
      var v = f.value + (f.unit && String(f.value).indexOf(f.unit) < 0 && f.unit.length <= 12 ? ' ' + f.unit : '');
      L.push('| ' + f.label + ' | ' + v + ' |');
      var m = String(f.value).match(/^([1-5])-/);
      if (m) ratings.push(parseInt(m[1], 10));
    });
    L.push('');
  });
  L.push('## 七、结论与建议（演示版本地生成）');
  L.push('');
  if (ratings.length) {
    var avg = (ratings.reduce(function (a, b) { return a + b; }, 0) / ratings.length);
    var minv = Math.min.apply(null, ratings), maxv = Math.max.apply(null, ratings);
    L.push('- **评分概况**：共 ' + ratings.length + ' 项评分，平均 **' + avg.toFixed(1) + ' 分**（区间 ' + minv + '–' + maxv + '）。');
    if (minv <= 2) L.push('- **优先改善项**：存在 ' + minv + ' 分项（明显不足），建议列为下一轮改进与复测重点。');
    else if (minv === 3) L.push('- **待观察项**：存在 3 分项（一般），建议补充重复测试确认是否稳定。');
    var prob = '';
    (p.sections || []).forEach(function (sec) {
      (sec.fields || []).forEach(function (f) {
        if (f.label.indexOf('问题') >= 0 && f.value) prob = f.value;
        if (f.label.indexOf('采购意向') >= 0 && f.value) L.push('- **采购意向**：' + f.value + '。');
      });
    });
    if (prob) L.push('- **客户主要问题**：' + prob + ' —— 建议在跟进时与客户确认判断基准，并与本次评分对照核实。');
  } else {
    L.push('- 本次未填写 1-5 分评分项，无法给出量化结论，建议补齐评分后复盘。');
  }
  L.push('');
  L.push('> 说明：本文件由**演示版**在本地按固定规则生成（不联网、不调用 AI），内容仅来自表单填写值。');
  return L.join('\n');
}
"""
src = src.replace("function runAI() {", local_md + "\nfunction runAI() {", 1)

src = src.replace(
    "function runAI() {\n  var miss = validate();\n  if (miss.length) { showStatus('err', '请先补齐：' + miss.slice(0, 6).join('、') + (miss.length > 6 ? ' 等 ' + miss.length + ' 项' : '')); return; }\n  var btn = $('aiBtn'); btn.disabled = true;",
    "function runAI() {\n  var miss = validate();\n  if (miss.length) { showStatus('err', '请先补齐：' + miss.slice(0, 6).join('、') + (miss.length > 6 ? ' 等 ' + miss.length + ' 项' : '')); return; }\n"
    "  if (window.__DEMO__ && window.__DEMO__.mockAI) {   /* 演示版：本地生成 */\n"
    "    var md = localStructureMD(payload());\n"
    "    $('mdWrap').style.display = ''; $('mdText').value = md;\n"
    "    $('mdBtn').disabled = false; $('copyBtn').disabled = false;\n"
    "    showStatus('ok', '✅ 已生成结构化报告（演示版本地生成，不联网）');\n"
    "    saveDraftSoon(); return;\n"
    "  }\n"
    "  var btn = $('aiBtn'); btn.disabled = true;", 1)

# ── 5) 顶栏/按钮文案与提交按钮 ───────────────────────────────
src = src.replace('<div class="t">🧪 测试报告定向收集<small>宝锐生物 · 销售提交 → AI 结构化 → 导出 MD</small></div>',
                  '<div class="t">🧪 测试报告定向收集 <span style="background:#fff3cd;color:#8a5a00;border-radius:5px;padding:1px 8px;font-size:11.5px;margin-left:6px">演示版</span>'
                  '<small>宝锐生物 · 演示模式：数据内置于页面，不联网、不写入服务器</small></div>', 1)
src = src.replace('<button class="btn primary" id="aiBtn" onclick="runAI()">✨ AI 结构化整理</button>',
                  '<button class="btn primary" id="aiBtn" onclick="runAI()">✨ 生成结构化报告</button>', 1)
src = src.replace('<button class="btn" id="subBtn" onclick="submitReport()">📤 提交报告</button>',
                  '<button class="btn" id="subBtn" onclick="demoSubmit()" style="display:none"></button>'
                  '<span style="font-size:12px;color:#8a5a00;background:#fff8e6;border:1px solid #f0d080;border-radius:7px;padding:6px 10px">演示版不提交到服务器，可直接导出 Markdown</span>', 1)

src = src.replace('</body>', '''<script>
/* 演示版补充：欢迎提示 + 禁用提交 */
(function () {
  try {
    var d = window.__DEMO__ || {};
    setTimeout(function () {
      var el = document.getElementById('draftBar');
      var hasText = el && (el.textContent || '').trim().length > 0;
      if (el && !hasText) {
        el.className = 'draft-bar warn'; el.style.display = 'flex';
        el.innerHTML = '🔸 演示版：内置 ' + ((d.orders || []).length) + ' 笔真实订单（脱敏后）· ' + ((d.skus || []).length) + ' 个货号 · '
          + ((d.schema && d.schema.product_count) || 0) + ' 个产品方向。数据仅存本机浏览器，刷新不丢（自动存草稿）。';
      }
    }, 1200);
  } catch (e) {}
})();
</script>
</body>''', 1)

# ── 6) 置顶「使用流程说明」卡片 + 样式 + 收起逻辑 ────────────
WF_CSS = """
.wf-steps{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:4px 0 12px}
.wf-step{background:#eef4fb;border:1px solid #cfe0f2;color:#12325b;border-radius:20px;padding:5px 12px;font-size:12.5px;font-weight:600;white-space:nowrap}
.wf-step b{color:#1a73c9;margin-right:4px}
.wf-arrow{color:#9aa8b8;font-size:12px}
.wf-table{width:100%;border-collapse:collapse;font-size:12.5px;margin:6px 0 10px}
.wf-table th{background:#f4f8fd;color:#42536b;text-align:left;padding:7px 10px;border-bottom:2px solid #e6eef7;font-weight:700;white-space:nowrap}
.wf-table td{border-bottom:1px solid #eef3f9;padding:7px 10px;vertical-align:top;color:#2b3a4a}
.wf-table td:first-child{font-weight:700;color:#12325b;white-space:nowrap}
.wf-notes{background:#f8fbff;border:1px dashed #cfe0f2;border-radius:8px;padding:9px 12px;font-size:12.5px;color:#42536b;line-height:1.9}
.wf-notes b{color:#12325b}
.wf-intro{background:#fff8e6;border:1px solid #f0d080;color:#7a5200;border-radius:8px;padding:10px 13px;font-size:12.5px;line-height:1.9;margin:6px 0 12px}
.wf-intro b{color:#8a5a00}
.wf-intro .lg{font-weight:700;color:#8a5a00}
"""
src = src.replace('</style>', WF_CSS + '</style>', 1)

WF_HTML = '''  <!-- ===== 使用流程说明（置顶） ===== -->
  <div class="card" id="wfCard" style="border-left:4px solid #1a73c9">
    <h3 style="cursor:pointer;user-select:none" onclick="toggleWF()">
      <span style="font-size:16px">📋</span> 使用流程说明
      <span class="badge">6 步 · 全程约 5 分钟</span>
      <span style="margin-left:auto;font-size:12.5px;color:#1a73c9;font-weight:600" id="wfToggle">收起 ▲</span>
    </h3>
    <div id="wfBody">
      <div class="wf-intro">
        <b>本工具用于「定向测试报告」收集场景</b>——如新产品/新批号实测、客户现场测试、专项验证等需要结构化留档并绑定具体订单的场合。<br>
        <span class="lg">⚠ 请注意：本工具不用于替代日常测试单反馈。</span>日常测试单反馈仍按原有流程提交，不进本表；本表一次测试 = 一份定向报告，须绑定订单号 / 客户 / 货号，并可导出 Markdown 存档。
      </div>
      <div class="wf-steps">
        <div class="wf-step"><b>①</b>选产品方向</div><div class="wf-arrow">→</div>
        <div class="wf-step"><b>②</b>关联订单/货号</div><div class="wf-arrow">→</div>
        <div class="wf-step"><b>③</b>填测试内容</div><div class="wf-arrow">→</div>
        <div class="wf-step"><b>④</b>上传图片</div><div class="wf-arrow">→</div>
        <div class="wf-step"><b>⑤</b>生成结构化报告</div><div class="wf-arrow">→</div>
        <div class="wf-step"><b>⑥</b>导出 / 提交</div>
      </div>
      <table class="wf-table">
        <thead><tr><th>步骤</th><th>谁来做</th><th>做什么</th><th>规则 / 说明</th></tr></thead>
        <tbody>
          <tr><td>① 选产品方向</td><td>销售</td><td>先选<b>产品类型</b>，再选该类型下的<b>产品方向</b></td><td>共 20 个方向 / 9 类；方向一旦选定，下方自动载入该方向专属的测试指标表单（不同方向指标不同）。唯一方向的类型会自动选中。</td></tr>
          <tr><td>② 关联订单与货号</td><td>销售</td><td>搜订单号（或客户名）选中 → 再搜货号选中</td><td>选中订单后<b>自动带出客户、负责销售、测试时间</b>（标注「自动带出」），无需重复手填；客户名可修改。货号支持按型号或中文名搜索。</td></tr>
          <tr><td>③ 填测试内容</td><td>销售 / 客户</td><td>按表单逐项填写实测数据与评分</td><td>带 <span style="color:#d93025;font-weight:700">*</span> 为必填；数据类填实测数值（含单位提示）；评分项为 1–5 分点选；问题与采购意向为下拉单选。</td></tr>
          <tr><td>④ 上传图片</td><td>销售</td><td>上传胶图 / 扩增曲线 / 片段分析图等</td><td>可多张，单张建议 &lt; 5 MB；也可传 PDF/Excel。图片会随报告一起归档。</td></tr>
          <tr><td>⑤ 生成结构化报告</td><td>系统</td><td>点「生成结构化报告」</td><td>只按你填写的内容整理，<b>不编造数据</b>；缺失项写「未提供」；并自动算出评分平均分、指出自相矛盾或需补充的数据。<br>正式版由 AI 生成（约 20–40 秒）；本演示版按固定规则在本地生成（约 2 秒，不联网）。</td></tr>
          <tr><td>⑥ 导出 / 提交</td><td>销售 / 管理</td><td>导出 .md 文档，或提交入库</td><td>报告可先编辑再导出；正式版提交后进入「已提交记录」，可随时查看详情、下载 Markdown。</td></tr>
        </tbody>
      </table>
      <div class="wf-notes">
        <b>草稿</b>：边填边自动保存（停止输入 0.8 秒后），关闭页面再打开会提示「恢复草稿」，不会丢。<br>
        <b>数据落点</b>（正式版）：一条记录 = 一个文件 <code>数据/test_reports/TR&lt;时间戳&gt;.json</code>，含原始填写值、图片路径、结构化报告。<br>
        <b>权限</b>：销售只见自己名下订单与自己提交的报告；admin / gm / 管理岗可见全部。<br>
        <b>校验</b>：必填项未填无法生成报告或提交；评分与「遇到的主要问题」若互相矛盾，报告中会明确提示复核。<br>
        <b>演示版差异</b>：数据内置于页面（不联网），AI 环节改由本地规则生成，且<b>不会提交到服务器</b>，可放心演示。
      </div>
    </div>
  </div>

'''
src = src.replace('  <div class="card">\n    <h3><span class="no">1</span>选择产品方向', WF_HTML + '  <div class="card">\n    <h3><span class="no">1</span>选择产品方向', 1)

WF_JS = """
/* 使用流程说明：展开 / 收起 */
function toggleWF() {
  var b = document.getElementById('wfBody'), t = document.getElementById('wfToggle');
  if (!b) return;
  var hide = b.style.display !== 'none';
  b.style.display = hide ? 'none' : '';
  if (t) t.textContent = hide ? '展开 ▼' : '收起 ▲';
}
"""
src = src.replace("/* ══════════ 初始化 ══════════ */", WF_JS + "\n/* ══════════ 初始化 ══════════ */", 1)

open(OUT, 'w', encoding='utf-8').write(src)
# JS 语法自检
js = re.findall(r'<script[^>]*>(.*?)</script>', src, re.S)
open('/tmp/_demo_check.js', 'w', encoding='utf-8').write('\n;\n'.join(js))
print('✅ 写出 %s（%.1f KB）' % (OUT, os.path.getsize(OUT) / 1024))
print('   内联：方向 %d ｜ 订单 %d ｜ 货号 %d ｜ JS 段 %d'
      % (len(schema.get('products', [])), len(orders), len(skus), len(js)))
