#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""程序化生成 5 张「案例场景」概念插画（SVG 方案，MiniMax 无额度时的回退）。
风格：瑞士几何 / 商务概念插画；宝锐蓝 #1F4E9C 主 + IKB #002FA7 点缀；
     无文字、无字母、无真人肖像、无写实人物（仅几何化图示）。
输出：_img_price_deck/<name>.svg（源码存档）+ <name>.png（1200 长边，供视觉核验/存档）
"""
import io
import os
import subprocess

BRAND = '#1F4E9C'
IKB = '#002FA7'
PAPER = '#FAFAF8'
INK = '#0A0A0A'
G2 = '#D4D4D2'
G3 = '#8A8A88'
OUT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类/培训与上手/培训/_img_price_deck'
W, H = 1200, 800
os.makedirs(OUT, exist_ok=True)


def _st(fill='none', stroke=None, sw=0, op=None, cap=None):
    s = ' fill="%s"' % fill
    if stroke:
        s += ' stroke="%s" stroke-width="%g"' % (stroke, sw)
    if op is not None:
        s += ' opacity="%g"' % op
    if cap:
        s += ' stroke-linecap="%s" stroke-linejoin="round"' % cap
    return s


def R(x, y, w, h, **k):
    rx = k.pop('rx', 0)
    rot = k.pop('rot', None)
    s = '<rect x="%g" y="%g" width="%g" height="%g"' % (x, y, w, h)
    if rx:
        s += ' rx="%g"' % rx
    s += _st(**k)
    if rot:
        s += ' transform="rotate(%g %g %g)"' % rot
    return s + '/>'


def C(cx, cy, r, **k):
    return '<circle cx="%g" cy="%g" r="%g"%s/>' % (cx, cy, r, _st(**k))


def L(x1, y1, x2, y2, **k):
    d = k.pop('dash', None)
    s = '<line x1="%g" y1="%g" x2="%g" y2="%g"' % (x1, y1, x2, y2)
    s += _st(**k)
    if d:
        s += ' stroke-dasharray="%s"' % d
    return s + '/>'


def P(d, **k):
    return '<path d="%s"%s/>' % (d, _st(**k))


def E(cx, cy, rx, ry, **k):
    return '<ellipse cx="%g" cy="%g" rx="%g" ry="%g"%s/>' % (cx, cy, rx, ry, _st(**k))


def G(inner, **k):
    a = ''
    for key, val in k.items():
        if val is not None:
            a += ' %s="%s"' % (key, val)
    return '<g%s>%s</g>' % (a, inner)


def dots(mat_n, sp, x0, y0, r=2.6, fill=IKB, op=.22):
    o = []
    for i in range(mat_n[0]):
        for j in range(mat_n[1]):
            o.append(C(x0 + i * sp, y0 + j * sp, r, fill=fill, op=op))
    return ''.join(o)


def arcs(cx, cy, radii, stroke=BRAND, op=.13, sw=2):
    return ''.join(C(cx, cy, r, stroke=stroke, sw=sw, op=op) for r in radii)


def person(cx, ytop, col, bh=98, hw=44, hr=21):
    """几何化图示人：圆头 + 圆角矩形身（无五官、非写实）。"""
    return (C(cx, ytop + hr, hr, fill=col) +
            R(cx - hw / 2, ytop + 2 * hr + 8, hw, bh, rx=hw / 2, fill=col))


def frame(body, w=W, h=H):
    return ('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 %d %d" width="%d" '
            'height="%d" role="img">'
            '<rect x="0" y="0" width="%d" height="%d" fill="%s"/>%s</svg>'
            % (w, h, w, h, w, h, PAPER, body))


# ── I1 谈判：桌前博弈 · 双方拉锯 ───────────────────────────────
def i1():
    o = [dots((7, 5), 26, 74, 70), arcs(1200, 800, (150, 214, 278))]
    # 桌面
    o.append(R(280, 452, 640, 20, rx=5, fill=IKB, op=.92))
    o.append(R(302, 472, 596, 52, rx=6, fill=BRAND))
    o.append(R(330, 524, 26, 66, fill=BRAND, op=.55))
    o.append(R(844, 524, 26, 66, fill=BRAND, op=.55))
    # 左方三名（几何图示）
    for i, cx in enumerate((152, 224, 296)):
        o.append(person(cx, 322, BRAND if i != 1 else IKB, bh=92 + i * 6))
    # 右方三名（镜像）
    for i, cx in enumerate((1048, 976, 904)):
        o.append(person(cx, 322, BRAND if i != 1 else IKB, bh=92 + i * 6))
    # 拉锯绳 + 张力
    o.append(P('M 300 402 Q 450 386 596 398', stroke=IKB, sw=9, cap='round'))
    o.append(P('M 604 398 Q 750 386 900 402', stroke=IKB, sw=9, cap='round'))
    o.append(R(566, 372, 68, 52, rx=14, rot=(45, 600, 398), fill=IKB))
    for i in range(3):
        o.append(L(344 + i * 16, 372, 336 + i * 16, 432, stroke=BRAND, sw=3, op=.5))
        o.append(L(856 - i * 16, 372, 864 - i * 16, 432, stroke=BRAND, sw=3, op=.5))
    o.append(R(600 - 3, 430, 6, 22, fill=BRAND, op=.5))
    return frame(''.join(o))


# ── I2 客户犹豫：左右权衡 ──────────────────────────────────────
def i2():
    o = [dots((6, 4), 26, 900, 74), arcs(0, 0, (150, 214, 278))]
    # 天平支柱 + 转动轴
    o.append(P('M 600 250 L 600 612', stroke=BRAND, sw=12, cap='round'))
    o.append(C(600, 244, 21, fill=IKB))
    # 倾斜横梁
    o.append(P('M 296 296 L 600 232 L 904 322', stroke=INK, sw=11, cap='round', op=.85))
    # 左盘（较重，下沉）—— 方案 A：三摞方块
    o.append(L(296, 300, 296, 372, stroke=G3, sw=3))
    o.append(P('M 214 372 L 378 372 L 356 418 L 236 418 Z', fill=BRAND))
    for i, (bw, bh) in enumerate(((120, 24), (96, 24), (70, 24))):
        o.append(R(296 - bw / 2, 348 - i * 26, bw, bh, rx=5, fill=IKB if i == 2 else BRAND))
    # 右盘（较轻，上抬）—— 方案 B：标签 + 单块
    o.append(L(904, 326, 904, 392, stroke=G3, sw=3))
    o.append(P('M 822 392 L 986 392 L 964 438 L 844 438 Z', fill=BRAND, op=.92))
    o.append(R(904 - 34, 330, 68, 40, rx=8, fill=IKB))
    o.append(C(904, 342, 7, fill=PAPER))
    o.append(R(904 - 22, 372, 44, 20, rx=4, fill=BRAND))
    # 底座
    o.append(R(520, 612, 160, 24, rx=6, fill=BRAND))
    # 底部左右分叉（虚线 + 箭头）
    o.append(L(600, 646, 398, 742, stroke=G3, sw=3, dash='12 10'))
    o.append(L(600, 646, 802, 742, stroke=G3, sw=3, dash='12 10'))
    o.append(P('M 372 730 L 398 750 L 424 730 Z', fill=IKB))
    o.append(P('M 828 730 L 802 750 L 776 730 Z', fill=IKB))
    return frame(''.join(o))


# ── I3 握手成交：合作达成 ─────────────────────────────────────
def i3():
    import math
    o = [dots((5, 5), 26, 70, 648), arcs(600, 404, (256, 316, 376), op=.10)]
    for a in (-70, -50, -30, 30, 50, 70, 110, 130, 150, 210, 230, 250):
        r1, r2 = 268, 344
        o.append(L(600 + r1 * math.cos(math.radians(a)), 404 + r1 * math.sin(math.radians(a)),
                   600 + r2 * math.cos(math.radians(a)), 404 + r2 * math.sin(math.radians(a)),
                   stroke=IKB, sw=2.4, op=.26))
    # 两个环相扣（合作 / 达成）
    o.append(C(492, 404, 152, stroke=IKB, sw=48))
    o.append(C(708, 404, 152, stroke=BRAND, sw=48))
    # 成交勾（环内）
    o.append(P('M 534 410 L 584 462 L 672 356', stroke=INK, sw=17, cap='round'))
    # 底衬圆（收束）
    o.append(C(600, 404, 172, stroke=BRAND, sw=2, op=.28))
    return frame(''.join(o))


# ── I4 太贵了：价格标签 · 取舍 ─────────────────────────────────
def i4():
    o = [dots((6, 4), 26, 880, 640), arcs(0, 800, (150, 214, 278))]
    # 标签（空白 · 无任何字样）
    tag = ('M 360 214 L 596 214 Q 620 214 620 238 L 620 560 Q 620 584 596 584 '
           'L 396 584 L 300 470 L 300 238 Q 300 214 324 214 Z')
    o.append(P(tag, fill=BRAND))
    o.append(C(372, 288, 17, fill=PAPER))
    o.append(L(280, 262, 372, 288, stroke=G3, sw=4))
    o.append(P('M 300 236 Q 268 250 280 262', stroke=G3, sw=4))
    # 拒绝斜杠
    o.append(R(232, 372, 460, 30, rx=15, rot=(-38, 462, 402), fill=IKB)) 
    # 硬币摞
    for i, (x, n) in enumerate(((760, 5), (868, 4), (976, 6))):
        for j in range(n):
            o.append(E(x, 604 - j * 24, 46, 13,
                       fill=IKB if (i + j) % 2 else BRAND, op=.92))
    # 跷跷板：硬币 vs 产品立方
    o.append(P('M 812 690 L 1054 646', stroke=INK, sw=11, cap='round', op=.85))
    o.append(P('M 933 640 L 900 706 L 966 706 Z', fill=BRAND))
    o.append(C(830, 674, 30, fill=IKB))
    o.append(R(1004, 570, 84, 84, rx=10, fill=BRAND))
    o.append(P('M 1016 700 L 1076 700', stroke=G3, sw=3))
    return frame(''.join(o))


# ── I5 乔布斯案例：更快马车 → 汽车 ─────────────────────────────
def i5():
    o = [dots((6, 4), 26, 900, 74), arcs(0, 800, (150, 214, 278))]
    o.append(L(64, 604, 1136, 604, stroke=G2, sw=3))
    # 马车
    o.append(R(150, 424, 250, 96, rx=12, fill=BRAND))
    o.append(P('M 164 424 L 214 350 L 336 350 L 386 424 Z', fill=BRAND, op=.62))
    o.append(C(210, 540, 50, stroke=BRAND, sw=11))
    o.append(C(344, 540, 50, stroke=BRAND, sw=11))
    for a in (0, 60, 120, 180, 240, 300):
        import math
        o.append(L(210 + 34 * math.cos(math.radians(a)), 540 + 34 * math.sin(math.radians(a)),
                   210 + 48 * math.cos(math.radians(a)), 540 + 48 * math.sin(math.radians(a)),
                   stroke=BRAND, sw=4, op=.7))
    o.append(L(150, 470, 74, 470, stroke=IKB, sw=6, cap='round'))
    # 转化箭头
    o.append(P('M 448 470 L 700 470', stroke=IKB, sw=15, cap='round'))
    o.append(P('M 736 470 L 686 442 L 686 498 Z', fill=IKB))
    # 汽车
    o.append(P('M 812 540 Q 812 470 884 456 L 1010 442 Q 1090 442 1096 500 '
               'L 1100 540 Q 1100 556 1082 556 L 830 556 Q 812 556 812 540 Z',
               fill=BRAND))
    o.append(P('M 874 452 Q 902 404 946 402 L 1004 402 Q 1036 404 1046 450 Z',
               fill=IKB, op=.85))
    o.append(C(880, 552, 42, stroke=BRAND, sw=10))
    o.append(C(1040, 552, 42, stroke=BRAND, sw=10))
    return frame(''.join(o))


FIGS = {'scene_tug': i1(), 'scene_weigh': i2(), 'scene_deal': i3(),
        'scene_price': i4(), 'jobs_cart': i5()}

if __name__ == '__main__':
    for n, s in FIGS.items():
        io.open(os.path.join(OUT, n + '.svg'), 'w', encoding='utf-8').write(s)
        print('  %-12s svg %d B' % (n, len(s.encode('utf-8'))))
    # 渲染 PNG（Chrome headless，1200 长边）供视觉核验
    html = '<meta charset="utf-8"><style>body{margin:0}img{display:block;width:1200px}</style>'
    for n in FIGS:
        open(os.path.join(OUT, '_prev_%s.html' % n), 'w').write(
            html + '<img src="%s.svg">' % n)
    chrome = ('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome')
    for n in FIGS:
        subprocess.run([chrome, '--headless=new', '--disable-gpu', '--hide-scrollbars',
                        '--screenshot=%s/%s.png' % (OUT, n), '--window-size=1200,800',
                        '--default-background-color=FAFAF8FF',
                        'file://%s/_prev_%s.html' % (OUT, n)],
                       capture_output=True)
        p = os.path.join(OUT, n + '.png')
        print('  %-12s png %s' % (n, (os.path.getsize(p) // 1024 if os.path.exists(p) else 'FAIL')))
