#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成《2026 秋季促销 · 阶段结果公布》海报（对内）。

输入：销售分析/科研销售_按人与区域_20260820-20260930.json
输出：
  销售分析/秋促科研战报_海报_3x4.html
  销售分析/秋促科研战报_海报_3x4.png（2160×2880，微信可转发）
不含客户名；不显示「有金额/编制」这类比率字眼。
"""
import base64
import io
import json
import os
import subprocess
import sys

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
SRC = os.path.join(ROOT, '销售分析', '科研销售_按人与区域_20260820-20260930.json')
HTML = os.path.join(ROOT, '销售分析', '秋促科研战报_海报_3x4.html')
PNG = os.path.join(ROOT, '销售分析', '秋促科研战报_海报_3x4.png')
LOGO = '/Users/liuxinyuan/work/公司资料/logo_transparent.png'
CHROME = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'

D = json.load(io.open(SRC, encoding='utf-8'))
W, H = 1080, 1440
logo_b64 = base64.b64encode(io.open(LOGO, 'rb').read()).decode()

ppl = [p for p in D['people'] if p['金额'] > 0]
top3, rest = ppl[:3], ppl[3:]
regs = D['regions']
mx = max(r['金额'] for r in regs) or 1
cum = 0.0
for p in ppl:
    cum += p['金额']
    p['累计'] = round(cum, 4)

PODIUM_H = {1: 206, 2: 150, 3: 122}
COLOR = {1: '#F5C542', 2: '#D8E2EE', 3: '#E0A96D'}


def podium(rank):
    p = [x for x in top3 if x['名次'] == rank]
    if not p:
        return '<div class="pod empty"></div>'
    p = p[0]
    return f"""<div class="pod r{rank}">
      <div class="pav" style="color:{COLOR[rank]}">{'①' if rank==1 else ('②' if rank==2 else '③')}</div>
      <div class="pn">{p['销售员']}</div>
      <div class="pr">{p['区域']}</div>
      <div class="pv" style="color:{COLOR[rank]}">{p['金额']:,.4f}<i>万</i></div>
      <div class="pb" style="height:{PODIUM_H[rank]}px;background:linear-gradient(180deg,{COLOR[rank]}33,{COLOR[rank]}0d);border-top:3px solid {COLOR[rank]}"></div>
    </div>"""


rest_rows = ''.join(
    f"""<div class="rl"><span class="rr">{p['名次']}</span><span class="rn">{p['销售员']}</span>
     <span class="rt">{p['区域']}</span><span class="rv">{p['金额']:,.4f}</span></div>""" for p in rest)

best_avg = max(ppl, key=lambda p: p['单均'])
best_cust = max(ppl, key=lambda p: p['客户数'])
lead_reg = regs[0]
hi_cards = f'''<div class="hi">
    <div class="hc"><div class="k">单均最高</div><div class="v">{best_avg['销售员']}</div><div class="s">{best_avg['单均']:,.3f} 万/单</div></div>
    <div class="hc"><div class="k">客户最多</div><div class="v">{best_cust['销售员']}</div><div class="s">{best_cust['客户数']} 家</div></div>
    <div class="hc"><div class="k">大区领先</div><div class="v">{lead_reg['大区'].replace('大区','')}</div><div class="s">{lead_reg['占比']}%</div></div>
  </div>'''

reg_bars = ''.join(f"""<div class="rb">
    <div class="rh"><b>{r['大区']}</b><span>{r['金额']:,.4f} 万 ｜ {r['占比']}%</span></div>
    <div class="rbar"><i style="width:{max(3, r['金额']/mx*100):.1f}%"></i></div>
  </div>""" for r in regs)

html = f"""<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8">
<title>2026 秋季促销 · 阶段结果公布</title><style>
*{{box-sizing:border-box;margin:0;padding:0}}
html,body{{width:{W}px;height:{H}px;overflow:hidden}}
body{{font-family:-apple-system,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  background:radial-gradient(120% 80% at 50% -10%,#1D5FC9 0%,#10408F 42%,#0A2450 100%);
  color:#fff;-webkit-print-color-adjust:exact !important;print-color-adjust:exact}}
.w{{position:relative;width:{W}px;height:{H}px;padding:34px 44px 30px;display:flex;flex-direction:column}}
.w:before{{content:'';position:absolute;inset:0;
  background:repeating-linear-gradient(115deg,rgba(255,255,255,.045) 0 2px,transparent 2px 26px);pointer-events:none}}
.glow{{position:absolute;width:640px;height:640px;border-radius:50%;filter:blur(70px);
  background:radial-gradient(circle,rgba(56,132,255,.42),transparent 68%);top:-260px;right:-190px}}
.glow2{{position:absolute;width:520px;height:520px;border-radius:50%;filter:blur(80px);
  background:radial-gradient(circle,rgba(245,197,66,.16),transparent 70%);bottom:-220px;left:-170px}}
.z{{position:relative;z-index:2;display:flex;flex-direction:column;height:100%}}
.hd{{display:flex;align-items:center;gap:16px;margin-bottom:16px}}
.chip{{background:#fff;border-radius:12px;padding:9px 15px;box-shadow:0 6px 20px rgba(0,0,0,.28)}}
.chip img{{height:38px;display:block}}
.hd .tt{{margin-left:auto;text-align:right}}
.hd .tt b{{display:block;font-size:19px;letter-spacing:.06em;font-weight:800}}
.hd .tt span{{font-size:12.5px;color:#A9C6F0;letter-spacing:.14em}}
.date{{display:inline-flex;align-items:center;gap:9px;align-self:flex-start;background:rgba(255,255,255,.13);
  border:1px solid rgba(255,255,255,.26);border-radius:999px;padding:7px 18px;font-size:14.5px;
  letter-spacing:.08em;margin-bottom:14px;backdrop-filter:blur(4px)}}
.date i{{width:7px;height:7px;border-radius:50%;background:#F5C542;display:block}}
h1{{font-size:52px;font-weight:900;line-height:1.1;letter-spacing:.01em;
  background:linear-gradient(92deg,#fff 30%,#BFD8FF 100%);-webkit-background-clip:text;
  -webkit-text-fill-color:transparent}}
h1 em{{font-style:normal;color:#F5C542;-webkit-text-fill-color:#F5C542}}
.sub{{font-size:16px;color:#A9C6F0;margin-top:9px;letter-spacing:.05em}}
.hero{{display:flex;gap:12px;margin:20px 0 6px}}
.hcard{{flex:1;background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.20);border-radius:14px;
  padding:13px 16px;backdrop-filter:blur(6px)}}
.hcard .k{{font-size:12.5px;color:#A9C6F0;letter-spacing:.08em}}
.hcard .v{{font-size:38px;font-weight:900;line-height:1.16;margin-top:2px;font-variant-numeric:tabular-nums}}
.hcard .v i{{font-size:15px;font-weight:600;color:#A9C6F0;font-style:normal;margin-left:3px}}
.hcard.gold{{background:linear-gradient(140deg,rgba(245,197,66,.24),rgba(245,197,66,.06));
  border-color:rgba(245,197,66,.48)}}
.hcard.gold .v{{color:#F5C542}} .hcard.gold .k{{color:#F3D98C}}
.sec{{font-size:14px;font-weight:800;letter-spacing:.16em;color:#8FB3E8;margin:16px 0 8px;display:flex;align-items:center;gap:10px}}
.sec:after{{content:'';flex:1;height:1px;background:linear-gradient(90deg,rgba(143,179,232,.45),transparent)}}
.pods{{display:flex;align-items:flex-end;gap:14px}}
.pod{{flex:1;text-align:center;position:relative}}
.pod.r1{{order:2}} .pod.r2{{order:1}} .pod.r3{{order:3}}
.pav{{font-size:30px;line-height:1;margin-bottom:4px}}
.pn{{font-size:25px;font-weight:900;letter-spacing:.02em}}
.pr{{font-size:12.5px;color:#A9C6F0;margin-top:2px}}
.pv{{font-size:24px;font-weight:900;margin:5px 0 7px;font-variant-numeric:tabular-nums}}
.pv i{{font-size:12px;font-style:normal;font-weight:600;color:#A9C6F0;margin-left:2px}}
.pb{{border-radius:10px 10px 0 0}}
.rank{{display:grid;grid-template-columns:1fr 1fr;gap:7px 22px;margin-top:2px}}
.rl{{display:flex;align-items:center;gap:9px;background:rgba(255,255,255,.075);border-radius:9px;
  padding:7px 12px;font-size:15.5px}}
.rr{{width:22px;height:22px;border-radius:50%;background:rgba(255,255,255,.16);font-size:12.5px;
  font-weight:800;display:flex;align-items:center;justify-content:center;color:#CFE0FA;flex:0 0 22px}}
.rn{{font-weight:800;min-width:58px}}
.rt{{color:#9FBCE4;font-size:12.5px}}
.rv{{margin-left:auto;font-weight:900;color:#EAF2FF;font-variant-numeric:tabular-nums}}
.rb{{margin-bottom:9px}}
.rh{{display:flex;justify-content:space-between;align-items:baseline;font-size:15px;margin-bottom:5px}}
.rh b{{font-size:16.5px;letter-spacing:.04em}} .rh span{{color:#CFE0FA;font-weight:700;font-variant-numeric:tabular-nums}}
.rbar{{height:15px;background:rgba(255,255,255,.12);border-radius:999px;overflow:hidden}}
.rbar i{{display:block;height:100%;border-radius:999px;
  background:linear-gradient(90deg,#4E9BFF,#1D5FC9);box-shadow:0 0 14px rgba(78,155,255,.5)}}
.hi{{display:flex;gap:12px}}
.hc{{flex:1;background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.20);border-radius:13px;
  padding:13px 14px;text-align:center;backdrop-filter:blur(6px)}}
.hc .k{{font-size:12.5px;color:#A9C6F0;letter-spacing:.1em}}
.hc .v{{font-size:25px;font-weight:900;margin:3px 0 2px;letter-spacing:.02em}}
.hc .s{{font-size:13px;color:#CFE0FA;font-weight:700;font-variant-numeric:tabular-nums}}
.foot{{margin-top:auto;padding-top:14px;border-top:1px solid rgba(255,255,255,.16);
  display:flex;align-items:center;gap:12px;font-size:12.5px;color:#9FBCE4}}
.foot b{{color:#fff;font-size:15px;letter-spacing:.06em}}
.foot .sl{{margin-left:auto;text-align:right;line-height:1.5}}
.foot .sl s{{text-decoration:none;color:#F5C542}}
</style></head><body><div class="w"><div class="glow"></div><div class="glow2"></div><div class="z">

  <div class="hd">
    <div class="chip"><img src="data:image/png;base64,{logo_b64}" alt="宝锐生物"></div>
    <div class="tt"><b>2026 秋季促销</b><span>阶段结果公布</span></div>
  </div>

  <div class="date"><i></i>2026.08.20 — 09.30</div>
  <h1>科研线 <em>阶段战报</em><br>销售金额排名</h1>
  <div class="sub">生命科学销售部 ｜ 按人 · 按大区（金额含税，单位：万元）</div>

  <div class="hero">
    <div class="hcard gold"><div class="k">阶段累计</div><div class="v">{D['total']:,.4f}<i>万</i></div></div>
    <div class="hcard"><div class="k">成交客户</div><div class="v">{D['stats']['客户数']}<i>家</i></div></div>
    <div class="hcard"><div class="k">有效订单</div><div class="v">{D['stats']['订单数']}<i>单</i></div></div>
  </div>

  <div class="sec">个 人 榜 · 前 三</div>
  <div class="pods">{podium(1)}{podium(2)}{podium(3)}</div>

  <div class="sec">个 人 榜 · 4 — {ppl[-1]['名次']}</div>
  <div class="rank">{rest_rows}</div>

  <div class="sec">大 区 对 决</div>
  {reg_bars}

  <div class="sec">阶 段 亮 点</div>
  {hi_cards}

  <div class="foot">
    <div><b>宝锐生物 BIORI BIOTECH</b><br>营销中心 · 销售管理</div>
    <div class="sl">守护生命健康，缔造美好生活<br><s>内部资料，请勿外传</s></div>
  </div>
</div></div></body></html>
"""

io.open(HTML, 'w', encoding='utf-8').write(html)
print('HTML → %s' % HTML)

# 渲染 2x PNG
r = subprocess.run([CHROME, '--headless=new', '--disable-gpu', '--hide-scrollbars',
                    '--force-device-scale-factor=2', '--run-all-compositor-stages-before-draw',
                    '--virtual-time-budget=15000', '--window-size=%d,%d' % (W, H),
                    '--screenshot=%s' % PNG, 'file://' + HTML],
                   capture_output=True, text=True, timeout=180)
print('Chrome exit=%s' % r.returncode)
try:
    from PIL import Image
    im = Image.open(PNG)
    print('PNG %s ｜ %s ｜ %.0f KB' % (im.size, '✅ 尺寸正确' if im.size == (W * 2, H * 2) else '❌ 尺寸异常',
                                      os.path.getsize(PNG) / 1024.0))
except Exception as e:
    print('读 PNG 失败:', e)
