#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""线上 CDN 最终取证（活动类型版）：拦截页点过 + 截图 + 断言。"""
import json
import ssl
import sys
import urllib.request
from playwright.sync_api import sync_playwright

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
CDN = 'https://bier-sales-d0gatbvlx288724e9-1458438710.tcloudbaseapp.com/workbench/index.html'
TUN = 'https://api.biorisales.site:8443'
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
sess = json.load(open(ROOT + '/数据/auth_sessions.json', encoding='utf-8'))
mine = sorted([(v['expire_at'], k, v) for k, v in sess.items() if v.get('name') == '刘新元'],
              reverse=True, key=lambda x: x[0])
TOKEN, IDENT = mine[0][1], dict(mine[0][2])
IDENT['open_id'] = 'ou_preview_only'
IDENT.pop('expire_at', None)

ok = True
def chk(label, cond, detail=''):
    global ok
    print('  %s %-46s %s' % ('✅' if cond else '❌', label, detail))
    if not cond:
        ok = False

print('① 隧道 API（线上后端）')
for m, exp in [('2026-07', 1867), ('2026-08', 2016), ('2026-09', 2093)]:
    req = urllib.request.Request(TUN + '/api/visit/stats?month=%s&scope=team' % m)
    req.add_header('Authorization', 'Bearer ' + TOKEN)
    try:
        j = json.load(urllib.request.urlopen(req, timeout=90, context=ctx))
        ty = j.get('types') or {}
        deps = j.get('departments') or []
        cons = (sum(d['types'].get('线下拜访', 0) for d in deps) == ty.get('线下拜访')
                and sum(d['types'].get('线上跟进', 0) for d in deps) == ty.get('线上跟进'))
        chk('%s 总数 %d ｜ 部门 %d ｜ 类型 %s' % (m, j.get('total'), len(deps),
                                                {k: ty[k] for k in ('线下拜访', '线上跟进', '陌拜') if k in ty}),
            j.get('total') == exp and cons and len(deps) == 3 + (1 if m != '2026-07' else 0))
    except Exception as e:
        chk('%s 接口' % m, False, str(e)[:80])

print('\n② CDN 页面（新前端已上线）')
try:
    b = urllib.request.urlopen(urllib.request.Request(CDN, headers={'User-Agent': 'probe'}),
                               timeout=30, context=ctx).read().decode('utf-8', 'ignore')
    for kw, name in [('vtCols', '活动类型列生成'), ('vtCells', '类型单元格'), ('atype', '读 atype'),
                     ('线下拜访', '线下拜访文案'), ('陌拜', '陌拜文案'), ('visitSetView', '维度切换'),
                     ('visitCrumb', '面包屑')]:
        chk('线上含 %s' % name, kw in b)
    chk('线上已无旧的「形式未标」口径', '形式未标' not in b and '可判定' not in b)
except Exception as e:
    chk('CDN 取回', False, str(e)[:80])

print('\n③ 真实 CDN 页面渲染（点过腾讯云拦截页）')
with sync_playwright() as p:
    br = p.chromium.launch(channel='chrome', headless=True)
    pg = br.new_page(viewport={'width': 1560, 'height': 1080})
    errs = []
    pg.on('pageerror', lambda e: errs.append(str(e)))
    pg.on('dialog', lambda d: d.accept())

    def handle_risk(tag):
        try:
            t = pg.evaluate("() => (document.body.innerText||'')")
            if '风险提醒' in pg.title() or '页面访问提示' in t:
                print('     [%s] 命中腾讯云「风险提醒」→ 点「确定访问」' % tag)
                pg.click('text=确定访问')
                pg.wait_for_timeout(3000)
        except Exception as e:
            print('     [%s] %s' % (tag, str(e)[:50]))

    pg.goto(CDN, wait_until='domcontentloaded')
    handle_risk('首次')
    pg.evaluate("""([tk, idn]) => { localStorage.setItem('bior_auth_token', tk);
        localStorage.setItem('bior_sw_user_v2', JSON.stringify(idn)); }""", [TOKEN, IDENT])
    pg.goto(CDN, wait_until='load')
    handle_risk('带token')
    try:
        pg.wait_for_function("() => typeof render === 'function'", timeout=60000)
    except Exception:
        chk('CDN 页面启动', False, 'render 未定义：%s' % errs[:2])
        br.close()
        sys.exit(1)
    pg.wait_for_timeout(1500)
    pg.evaluate("""() => { window.state = window.state || {};
        window.state.user = JSON.parse(JSON.stringify(%s));
        if (typeof showApp === 'function') showApp(); }""" % json.dumps(IDENT, ensure_ascii=False))
    pg.wait_for_timeout(1500)
    pg.evaluate("() => { visitView='dept'; visitDrill={dept:'',sales:''}; visitHubState='see'; state.tab='visitStats'; render(); }")
    pg.wait_for_timeout(1200)
    pg.evaluate("() => visitSetMonth('2026-09')")
    pg.wait_for_timeout(6000)
    heads = pg.evaluate("() => [...document.querySelectorAll('#visitBody thead th')].map(e=>e.innerText.trim())")
    chk('线上表头 = 活动类型', all(h in heads for h in ('线下拜访', '线上跟进', '陌拜')), str(heads))
    tot = pg.evaluate("() => (window.__vj||{}).total")
    chk('线上 9 月总数 2093', tot == 2093, str(tot))
    pg.screenshot(path='/tmp/p2d_live_dept.png')
    top = pg.evaluate("""() => { const d=(window.__vj.departments||[]).find(x=>x.dept==='生命科学销售部');
        return d&&d.sales.length?d.sales[0].name:null; }""")
    pg.evaluate("() => visitDrillTo('生命科学销售部','')")
    pg.wait_for_timeout(1200)
    pg.screenshot(path='/tmp/p2d_live_sales.png')
    pg.evaluate("(n) => visitDrillTo('生命科学销售部', n)", top)
    pg.wait_for_timeout(1500)
    pg.evaluate("() => { const b=document.querySelector('#visitBody tbody tr button'); if(b) b.click(); }")
    pg.wait_for_timeout(1000)
    pg.screenshot(path='/tmp/p2d_live_cust.png')
    chk('线上下钻到销售 %s' % top, pg.evaluate("() => document.querySelectorAll('#visitBody tbody tr').length") >= 1)
    chk('线上 0 JS 错误', len(errs) == 0, str(errs[:2]))
    br.close()

print('\n%s' % ('✅ 线上已就绪' if ok else '❌ 线上有问题'))
sys.exit(0 if ok else 1)
