#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""拜访与活动：前端加「按部门 / 按销售 / 按客户」下钻 UI（管理者可见维度切换）。"""
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')]

# ── 1) 状态变量 ──
A_OLD = "var visitQ = '';"
A_NEW = "var visitQ = '';\nvar visitDim = 'dept';                 /* dept | cust（仅管理者可切）*/\nvar visitDrill = { dept: '', sales: '' };  /* 下钻位置 */"

# ── 2) 辅助函数（插在 renderVisitStats 前）──
B_ANCHOR = "function renderVisitStats(main) {"
B_NEW = r'''function visitSetDim(d) { visitDim = d; visitDrill = { dept: '', sales: '' }; render(); }
function visitDrillTo(dept, sales) {
  visitDrill = { dept: dept || '', sales: sales || '' };
  if (window.__vj) renderVisitBody(window.__vj);
}
function visitCrumb() {
  var parts = ['<a href="#" onclick="visitDrillTo(\'\',\'\');return false" style="color:var(--pri)">全部部门</a>'];
  if (visitDrill.dept) parts.push('<a href="#" onclick="visitDrillTo(\'' + esc(visitDrill.dept) + '\',\'\');return false" style="color:var(--pri)">' + esc(visitDrill.dept) + '</a>');
  if (visitDrill.sales) parts.push('<span style="font-weight:700">' + esc(visitDrill.sales) + '</span>');
  return '<div class="text-muted" style="font-size:12.5px;margin:0 0 8px">' + parts.join(' <b>›</b> ') + '</div>';
}
function visitEmpty() {
  return '<div class="todo-empty"><span class="icon">📈</span>该月暂无活动' +
    '<br><span style="font-size:12px">点右上「＋ 记一次拜访/跟进」，或到「客户」里发起拜访</span></div>';
}
var visitActSeq = 0;
function visitCustTable(rows) {
  visitActSeq = 0;
  var 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 style="white-space:nowrap">' +
        '<button class="btn btn-sm" onclick="visitToggle(' + i + ')">活动明细</button> ' +
        '<button class="btn btn-sm" onclick="visitPrepGo(&quot;' + esc(c.customer) + '&quot;)">去前准备</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 = visitActSeq++;
        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>';
  });
  return '<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:190px"></th></tr></thead><tbody>' + body + '</tbody></table></div>';
}

'''
# ── 3) 头部加维度切换 ──
C_OLD = """        '<button class="btn btn-sm" onclick="visitSetMonth(today().slice(0,7));">本月</button>' +
        '<button class="btn btn-primary btn-sm" style="margin-left:auto" onclick="visitSetState(\\'rec\\')">＋ 记一次拜访/跟进</button>' +"""
C_NEW = """        '<button class="btn btn-sm" onclick="visitSetMonth(today().slice(0,7));">本月</button>' +
        (mgr ? '<span style="width:12px"></span><div class="todo-filters">' +
                 '<button class="btn btn-sm ' + (visitDim === 'dept' ? 'active' : '') + '" onclick="visitSetDim(\\'dept\\')">🏢 按部门</button>' +
                 '<button class="btn btn-sm ' + (visitDim === 'cust' ? 'active' : '') + '" onclick="visitSetDim(\\'cust\\')">📋 按客户</button>' +
               '</div>' : '') +
        '<button class="btn btn-primary btn-sm" style="margin-left:auto" onclick="visitSetState(\\'rec\\')">＋ 记一次拜访/跟进</button>' +"""

# ── 4) 替换 renderVisitBody ──
D_START = "function renderVisitBody(j) {"
D_END = "function visitToggle(i) {"
D_NEW = r'''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;
  }
  window.__vj = j;
  var mgr = visitIsMgr();
  var dim = mgr ? visitDim : 'cust';

  var html = '<div class="stats-grid" style="margin-bottom:10px">' +
    kpiCard('线下拜访次数', j.offline_count, '#1F4E9C', visitScopeLabel(j.scope) + ' · ' + esc(j.month)) +
    kpiCard('线上跟进次数', j.online_count, '#002FA7', visitScopeLabel(j.scope) + ' · ' + esc(j.month)) +
    kpiCard('当月活动合计', j.total, '#5f6368', (j.unclassified ? ('未标形式 ' + j.unclassified + ' 条') : '全部已标形式')) +
    '</div>' + visitTrend(j);

  if (dim === 'dept') {
    var deps = j.departments || [];
    html += visitCrumb();

    if (!visitDrill.dept) {                       /* 一级：部门 */
      html += '<div class="text-muted" style="font-size:12px;margin-bottom:6px">点「下钻」→ 该部门的销售 → 再点销售看客户 → 再点客户看活动明细</div>';
      if (!deps.length) { b.innerHTML = html + visitEmpty(); return; }
      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:80px">销售数</th><th style="width:90px"></th></tr></thead><tbody>' +
        deps.map(function (d) {
          return '<tr><td><b>' + esc(d.dept) + '</b></td>' +
            '<td><b style="color:#1F4E9C">' + d.offline + '</b></td>' +
            '<td><b style="color:#002FA7">' + d.online + '</b></td>' +
            '<td>' + d.total + '</td><td>' + (d.sales_count || 0) + '</td>' +
            '<td><button class="btn btn-sm" onclick="visitDrillTo(&quot;' + esc(d.dept) + '&quot;,&quot;&quot;)">下钻 →</button></td></tr>';
        }).join('') + '</tbody></table></div>';
      return;
    }

    var dep = null;
    for (var i = 0; i < deps.length; i++) { if (deps[i].dept === visitDrill.dept) { dep = deps[i]; break; } }
    if (!dep) { b.innerHTML = html + '<div class="error-box" style="margin:12px">该部门本月无数据</div>'; return; }

    if (!visitDrill.sales) {                      /* 二级：销售 */
      b.innerHTML = html + '<div style="overflow-x:auto"><table><thead><tr><th>销售</th>' +
        '<th style="width:80px">区域</th><th style="width:90px">线下拜访</th><th style="width:90px">线上跟进</th>' +
        '<th style="width:80px">合计</th><th style="width:80px">客户数</th><th style="width:90px"></th></tr></thead><tbody>' +
        (dep.sales || []).map(function (s) {
          return '<tr><td><b>' + esc(s.name) + '</b></td>' +
            '<td class="text-muted">' + esc(s.region || '—') + '</td>' +
            '<td><b style="color:#1F4E9C">' + s.offline + '</b></td>' +
            '<td><b style="color:#002FA7">' + s.online + '</b></td>' +
            '<td>' + s.total + '</td><td>' + (s.customer_count || 0) + '</td>' +
            '<td><button class="btn btn-sm" onclick="visitDrillTo(&quot;' + esc(visitDrill.dept) + '&quot;,&quot;' + esc(s.name) + '&quot;)">下钻 →</button></td></tr>';
        }).join('') + '</tbody></table></div>';
      return;
    }

    var sal = null;
    (dep.sales || []).forEach(function (s) { if (s.name === visitDrill.sales) { sal = s; } });
    if (!sal) { b.innerHTML = html + '<div class="error-box" style="margin:12px">该销售本月无数据</div>'; return; }

    b.innerHTML = html + visitCustTable(sal.customers || []);   /* 三级：客户 → 活动明细 */
    return;
  }

  /* 按客户（扁平） */
  var all = j.customers || [];
  var rows = visitQ ? all.filter(function (c) { return (c.customer || '').indexOf(visitQ) >= 0; }) : all;
  html += '<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px;flex-wrap:wrap">' +
    '<input class="input" style="max-width:240px" placeholder="按客户名筛选…" value="' + esc(visitQ) + '" ' +
      'oninput="visitSetQ(this.value);clearTimeout(window.__vq);window.__vq=setTimeout(function(){renderVisitBody(window.__vj);},280)">' +
    '<span class="text-muted" style="font-size:12px">' + rows.length + ' 家客户</span></div>';
  if (!rows.length) { b.innerHTML = html + visitEmpty(); return; }
  b.innerHTML = html + visitCustTable(rows);
}

'''


def main():
    apply = '--apply' in sys.argv
    ts = time.strftime('%Y%m%d-%H%M%S')
    bak = os.path.join(ROOT, '_bak_p2b_drill_%s' % ts)
    print('拜访与活动·前端下钻补丁 —— %s\n' % ('APPLY' if apply else 'DRY-RUN'))
    allok = 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 [('A 状态变量', A_OLD, A_NEW),
                                ('B 下钻辅助', B_ANCHOR, B_NEW + B_ANCHOR),
                                ('C 头部维度切换', C_OLD, C_NEW)]:
            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)
        i = s.find(D_START); j = s.find(D_END, i)
        if i < 0 or j < 0:
            ok = False
            print('  ❌ D renderVisitBody 区间未找到')
        else:
            print('  ✅ %-16s 替换 %d 字符' % ('D 下钻渲染', j - i))
            s = s[:i] + D_NEW + s[j:]
        if not ok:
            allok = 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)
    if apply and allok:
        print('\n  原文件备份 → %s' % bak)
    print('\n%s' % ('全部命中 ✅' if allok else '有未命中 ❌'))
    return 0 if allok else 1


sys.exit(main())
