# -*- coding: utf-8 -*-
"""佰奥莱博简报用图 v2（Pillow 绘制，零外部依赖）：3 张 PNG"""
import json, os
from PIL import Image, ImageDraw, ImageFont

W = os.path.expanduser('~/Desktop/Hermes输出-工作类')
D = os.path.join(W, '数据')
OUT = os.path.join(W, '销售分析/佰奥莱博_三年简报_图')
os.makedirs(OUT, exist_ok=True)
data = json.load(open(os.path.join(D, '_bai_3y_data.json')))
Y = data['yearly']

BLUE = (21, 101, 192)
BLUE_D = (13, 71, 161)
BLUE_L = (144, 202, 249)
ORANGE = (242, 153, 74)
GRAY = (95, 107, 122)
LIGHT = (238, 243, 250)
WHITE = (255, 255, 255)

FONT_PATHS = ['/System/Library/Fonts/PingFang.ttc',
              '/System/Library/Fonts/Hiragino Sans GB.ttc',
              '/System/Library/Fonts/Supplemental/Songti.ttc']

def font(size):
    for p in FONT_PATHS:
        if os.path.exists(p):
            try:
                return ImageFont.truetype(p, size)
            except Exception:
                continue
    return ImageFont.load_default()

def ctext(d, xy_center, text, f, fill):
    x, y = xy_center
    b = d.textbbox((0, 0), text, font=f)
    d.text((x - (b[2] - b[0]) / 2 - b[0], y - (b[3] - b[1]) / 2 - b[1]), text, font=f, fill=fill)

def fmt(v, nd=2):
    """四舍五入（避免 float 二进制导致的 43.745 -> 43.74）"""
    from decimal import Decimal, ROUND_HALF_UP
    q = Decimal(1).scaleb(-nd)
    return str(Decimal(repr(float(v))).quantize(q, rounding=ROUND_HALF_UP))

def save(im, name):
    p = os.path.join(OUT, name)
    im.save(p, quality=95)
    print('saved', p, im.size)

def chart_year():
    w, h = 980, 440
    im = Image.new('RGB', (w, h), WHITE)
    d = ImageDraw.Draw(im)
    pad_l, pad_r, pad_t, pad_b = 100, 40, 64, 78
    plot_w, plot_h = w - pad_l - pad_r, h - pad_t - pad_b
    vals = [Y['2024']['amount'] / 1e4, Y['2025']['amount'] / 1e4, Y['2026']['amount'] / 1e4]
    labels = ['2024年', '2025年', '2026年1-9月']
    vmax = 120
    d.text((pad_l - 26, 20), '近三年销售额（价税合计，万元）', font=font(24), fill=BLUE_D)
    for g in range(5):
        v = vmax / 4 * g
        y = pad_t + plot_h - plot_h * (v / vmax)
        d.line([(pad_l, y), (pad_l + plot_w, y)], fill=LIGHT, width=2)
        d.text((pad_l - 46, y - 9), f'{v:.0f}', font=font(15), fill=GRAY)
    bw = 140
    gaps = (plot_w - bw * 3) / 3.4
    for i, (v, lb) in enumerate(zip(vals, labels)):
        x = pad_l + gaps * 0.6 + i * (bw + gaps)
        bh = plot_h * v / vmax
        y0 = pad_t + plot_h - bh
        color = BLUE if i < 2 else ORANGE
        d.rounded_rectangle([x, y0, x + bw, pad_t + plot_h], radius=8, fill=color)
        ctext(d, (x + bw / 2, y0 - 20), fmt(v), font(21), BLUE_D)
        ctext(d, (x + bw / 2, pad_t + plot_h + 22), lb, font(16), GRAY)
        if i == 1:
            ctext(d, (x + bw / 2, y0 + 34), f'+{Y["yoy_2025"]:.1f}%', font(16), WHITE)
        if i == 2:
            ctext(d, (x + bw / 2, y0 + 34), f'{Y["yoy_2026"]:.1f}%', font(16), WHITE)
    d.line([(pad_l, pad_t + plot_h), (pad_l + plot_w, pad_t + plot_h)], fill=(200, 210, 225), width=2)
    save(im, 'chart_year.png')

def chart_month():
    w, h = 980, 400
    im = Image.new('RGB', (w, h), WHITE)
    d = ImageDraw.Draw(im)
    pad_l, pad_r, pad_t, pad_b = 92, 40, 60, 70
    plot_w, plot_h = w - pad_l - pad_r, h - pad_t - pad_b
    m25 = [Y['2025']['monthly'].get(f'2025-{m:02d}', 0) / 1e4 for m in range(1, 13)]
    m26 = [Y['2026']['monthly'].get(f'2026-{m:02d}', 0) / 1e4 for m in range(1, 10)]
    vmax = 30
    d.text((pad_l - 22, 18), '月度销售额对比（万元）：2025 全年 vs 2026 年 1-9 月', font=font(22), fill=BLUE_D)
    for g in range(5):
        v = vmax / 4 * g
        y = pad_t + plot_h - plot_h * v / vmax
        d.line([(pad_l, y), (pad_l + plot_w, y)], fill=LIGHT, width=2)
        d.text((pad_l - 40, y - 9), f'{v:.0f}', font=font(15), fill=GRAY)
    step = plot_w / 12.6
    for i in range(1, 13):
        d.text((pad_l + step * (i - 0.3) - 6, pad_t + plot_h + 12), f'{i}月', font=font(14), fill=GRAY)
    p25 = [(pad_l + step * (i + 0.7), pad_t + plot_h - plot_h * (v / vmax)) for i, v in enumerate(m25)]
    p26 = [(pad_l + step * (i + 0.7), pad_t + plot_h - plot_h * (v / vmax)) for i, v in enumerate(m26)]
    d.line(p25, fill=BLUE_L, width=4, joint='curve')
    d.line(p26, fill=ORANGE, width=4, joint='curve')
    for x, y in p25:
        d.ellipse([x - 4, y - 4, x + 4, y + 4], fill=BLUE_L)
    for x, y in p26:
        d.ellipse([x - 5, y - 5, x + 5, y + 5], fill=ORANGE)
    lx, ly = pad_l + 6, pad_t + 4
    d.line([(lx, ly), (lx + 30, ly)], fill=BLUE_L, width=4)
    d.text((lx + 38, ly - 9), '2025年', font=font(15), fill=GRAY)
    d.line([(lx + 130, ly), (lx + 160, ly)], fill=ORANGE, width=4)
    d.text((lx + 168, ly - 9), '2026年', font=font(15), fill=GRAY)
    d.line([(pad_l, pad_t + plot_h), (pad_l + plot_w, pad_t + plot_h)], fill=(200, 210, 225), width=2)
    save(im, 'chart_month.png')

def chart_mix():
    w, h = 980, 300
    im = Image.new('RGB', (w, h), WHITE)
    d = ImageDraw.Draw(im)
    pad_l = 152
    d.text((pad_l - 30, 16), 'FMD 直扩系列占客户销售额比重（%）', font=font(22), fill=BLUE_D)
    shares = [Y['2024']['fmd_share'], Y['2025']['fmd_share'], Y['2026']['fmd_share']]
    labels = ['2024年', '2025年', '2026年1-9月']
    amounts = [Y['2024']['fmd_amount'] / 1e4, Y['2025']['fmd_amount'] / 1e4, Y['2026']['fmd_amount'] / 1e4]
    bar_h, gap, top = 40, 28, 66
    full_w = w - pad_l - 270
    for i, (s, lb, a) in enumerate(zip(shares, labels, amounts)):
        y = top + i * (bar_h + gap)
        d.text((pad_l - 118, y + 10), lb, font=font(15), fill=GRAY)
        d.rounded_rectangle([pad_l, y, pad_l + full_w, y + bar_h], radius=6, fill=LIGHT)
        bl = full_w * s / 100
        d.rounded_rectangle([pad_l, y, pad_l + max(bl, 10), y + bar_h], radius=6,
                            fill=BLUE if s > 50 else BLUE_L)
        d.text((pad_l + max(bl, 10) + 12, y + 9), f'{s:.1f}%   ({fmt(a)} 万元)',
               font=font(16), fill=BLUE_D)
    save(im, 'chart_mix.png')

chart_year(); chart_month(); chart_mix()
