#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""P1 前端补丁：新增「拜访视图」Tab（工具/index.html + 工具/app.html 同改）。

改动面：
  V1 TABS 增加 visitStats（group='biz'，da/ls 两条业务线可见）
  V2 render() 分发器加 case
  V3 renderVisitStats / renderVisitBody / visitToggle / visitDetail
只用工作台已有的 class（stat-card / tag / todo-filters / error-box），不依赖未知样式类。
"""
import io
import os
import shutil
import sys
import time

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
FILES = [os.path.join(ROOT, '工具', 'index.html'), os.path.join(ROOT, '工具', 'app.html')]

V1_OLD = "  { id: 'dashboard', group: 'biz', label: '看板', icon: '📊', lines: ['da','ls'] },\n"
V1_NEW = V1_OLD + "  { id: 'visitStats', group: 'biz', label: '拜访视图', icon: '📈', lines: ['da','ls'] },\n"

V2_OLD = "    case 'todos': renderTodos(main); break;"
V2_NEW = "    case 'todos': renderTodos(main); break;\n    case 'visitStats': renderVisitStats(main); break;"

V3_JS = r'''/* ---------- 拜访视图（P1）：当月线下拜访次数 / 线上跟进次数 ---------- */
var visitMonth = '';
function renderVisitStats(main) {
  if (!visitMonth) visitMonth = today().slice(0, 7);
  main.innerHTML = '<div class="card"><div class="card-header" style="flex-wrap:wrap;gap:10px">' +
    '<h3>📈 拜访视图 <span class="tag tag-blue">' + esc(visitMonth) + '</span></h3>' +
    '<div class="todo-filters"><input type="month" class="input" id="visitMonth" style="width:150px" value="' + esc(visitMonth) + '" onchange="visitMonth=this.value;render()">' +
    '<button class="btn btn-sm" onclick="visitMonth=today().slice(0,7);render()">本月</button></div></div>' +
    '<div class="card-body" id="visitBody"><div class="text-muted" style="padding:14px">加载中…</div></div></div>';
  apiFetch('/api/visit/stats?month=' + encodeURIComponent(visitMonth), { cache: 'no-store' })
    .then(function (r) { return r.json(); })
    .then(function (j) { renderVisitBody(j); })
    .catch(function (e) {
      var b = document.getElementById('visitBody');
      if (b) b.innerHTML = '<div class="error-box" style="margin:12px">加载失败：' + esc(String(e && e.message || e)) + '</div>';
    });
}
function kpiCard(label, val, color, sub) {
  return '<div class="stat-card" style="border-left:4px solid ' + color + '">' +
    '<div class="text-muted" style="font-size:12px">' + label + '</div>' +
    '<div class="value" style="color:' + color + '">' + val + '</div>' +
    '<div class="text-muted" style="font-size:12px">' + (sub || '') + '</div></div>';
}
function renderVisitBody(j) {
  var b = document.getElementById('visitBody'); if (!b) return;
  if (!j || !j.ok) { b.innerHTML = '<div class="error-box" style="margin:12px">' + esc((j && j.error) || '加载失败') + '</div>'; return; }
  var rows = j.customers || [];
  var html = '<div class="stats-grid" style="margin-bottom:14px">' +
    kpiCard('线下拜访次数', j.offline_count, '#1F4E9C', '当月活动形式 = 线下拜访') +
    kpiCard('线上跟进次数', j.online_count, '#002FA7', '当月活动形式 = 线上跟进') +
    kpiCard('当月活动合计', j.total, '#5f6368', (j.unclassified ? ('其中未标形式 ' + j.unclassified + ' 条') : '全部已标形式')) +
    '</div>';
  if (!rows.length) {
    b.innerHTML = html + '<div class="todo-empty"><span class="icon">📈</span>该月暂无活动' +
      '<br><span style="font-size:12px">在「活动录入」提交后即计入</span></div>';
    return;
  }
  var ai = 0, body = '';
  rows.forEach(function (c, i) {
    body += '<tr><td>' + esc(c.customer) + '</td>' +
      '<td><b style="color:#1F4E9C">' + c.offline + '</b></td>' +
      '<td><b style="color:#002FA7">' + c.online + '</b></td>' +
      '<td>' + c.total + '</td>' +
      '<td><button class="btn btn-sm" onclick="visitToggle(' + i + ')">活动明细</button></td></tr>' +
      '<tr id="visitActs' + i + '" style="display:none"><td colspan="5" style="background:#f8f9fa;padding:8px 12px">' +
      (c.acts || []).map(function (a) {
        var n = ai++;
        var ch = (a.channel === 'offline') ? '<span class="tag tag-blue">线下</span>'
               : (a.channel === 'online') ? '<span class="tag tag-gray">线上</span>' : '<span class="tag tag-orange">未标</span>';
        return '<div style="padding:5px 0;border-bottom:1px dashed #e5e7eb">' + ch +
          ' <b>' + esc(a.date || '') + '</b> ｜ ' + esc(a.type || '') + ' ｜ ' + esc(a.sales || '') + ' ｜ ' + esc(a.id || '') +
          ' <a href="#" onclick="visitDetail(&quot;' + esc(a.id || '') + '&quot;,' + n + ');return false" style="color:var(--pri)">看详情 →</a>' +
          '<div id="visitDetail' + n + '"></div></div>';
      }).join('') + '</td></tr>';
  });
  b.innerHTML = html + '<div style="overflow-x:auto"><table><thead><tr><th>客户</th>' +
    '<th style="width:90px">线下拜访</th><th style="width:90px">线上跟进</th><th style="width:80px">合计</th><th style="width:110px"></th>' +
    '</tr></thead><tbody>' + body + '</tbody></table></div>';
}
function visitToggle(i) {
  var el = document.getElementById('visitActs' + i);
  if (el) el.style.display = (el.style.display === 'none' ? '' : 'none');
}
function visitDetail(id, n) {
  var host = document.getElementById('visitDetail' + n); if (!host) return;
  host.innerHTML = '<div class="text-muted" style="font-size:12px;padding:4px 0">加载中…</div>';
  apiFetch('/api/activity/detail?id=' + encodeURIComponent(id), { cache: 'no-store' })
    .then(function (r) { return r.json(); })
    .then(function (j) {
      if (!j.ok) { host.innerHTML = '<div class="error-box" style="margin:6px 0">' + esc(j.error || '加载失败') + '</div>'; return; }
      var rec = j.activity || {};
      host.innerHTML = '<pre style="white-space:pre-wrap;font-size:12px;margin:6px 0;max-height:320px;overflow:auto;' +
        'background:#fff;padding:10px;border:1px solid #e5e7eb;border-radius:6px">' + esc(rec.feishu_text || '') + '</pre>';
    })
    .catch(function (e) {
      host.innerHTML = '<div class="error-box" style="margin:6px 0">' + esc(String(e && e.message || e)) + '</div>';
    });
}
function renderTodos(main) {'''

V3_OLD = "function renderTodos(main) {"

PAIRS = [
    ('V1 TABS', V1_OLD, V1_NEW),
    ('V2 分发器', V2_OLD, V2_NEW),
    ('V3 拜访视图函数', V3_OLD, V3_JS),
]


def main():
    apply = '--apply' in sys.argv
    print('P1 拜访视图补丁 —— %s\n' % ('APPLY' if apply else 'DRY-RUN'))
    ts = time.strftime('%Y%m%d-%H%M%S')
    bak = os.path.join(ROOT, '_bak_p1_visit_%s' % ts)
    ok_all = True
    for f in FILES:
        s = io.open(f, encoding='utf-8').read()
        print('=== %s ===' % os.path.basename(f))
        ok = True
        for label, old, new in PAIRS:
            n = s.count(old)
            if n != 1:
                ok = False
            print('  %s %-16s 命中 %d' % ('✅' if n == 1 else '❌', label, n))
            if n == 1:
                s = s.replace(old, new, 1)
        if not ok:
            ok_all = False
            print('  → 该文件不落盘')
            continue
        if apply:
            os.makedirs(bak, exist_ok=True)
            shutil.copy2(f, os.path.join(bak, os.path.basename(f)))
            io.open(f, 'w', encoding='utf-8').write(s)
            print('  已写（备份 %s）｜%d → %d 字节' % (bak, os.path.getsize(f), len(s.encode('utf-8'))))
    print('\n%s' % ('全部命中 ✅' if ok_all else '有未命中 ❌'))
    if not apply and ok_all:
        print('干跑通过，未落盘。')
    return 0 if ok_all else 1


sys.exit(main())
