#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""把六人年度目标责任书达成做成一张总表，插入10月汇报PPT P5之后。"""
import json, os
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from pptx.oxml.ns import qn
from lxml import etree

ROOT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
SRC = os.path.join(ROOT, '经营分析/月报/2026年10月销售部工作汇报_草稿_20261108.pptx')
OUT = os.path.join(ROOT, '经营分析/月报/2026年10月销售部工作汇报_草稿_20261108_v3.pptx')
LOGO = '/Users/liuxinyuan/work/公司资料/logo_transparent.png'
DATA = json.load(open(os.path.join(ROOT, '数据/年度目标责任书_六人达成_20261108.json'), encoding='utf-8'))

NAVY = RGBColor(0x0B, 0x2A, 0x4A)
BLUE = RGBColor(0x1F, 0x6F, 0xEB)
LIGHT = RGBColor(0xEA, 0xF2, 0xFB)
PALE = RGBColor(0xF5, 0xF8, 0xFC)
GREY = RGBColor(0x5B, 0x6B, 0x7F)
MIDGREY = RGBColor(0x8A, 0x99, 0xAA)
RED = RGBColor(0xC0, 0x39, 0x2B)
AMBER = RGBColor(0xB7, 0x79, 0x1F)
GREEN = RGBColor(0x1E, 0x84, 0x49)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)


def set_run(run, size=9, color=NAVY, bold=False):
    run.font.size = Pt(size)
    run.font.bold = bold
    run.font.color.rgb = color
    run.font.name = 'Times New Roman'
    rPr = run._r.get_or_add_rPr()
    ea = rPr.find(qn('a:ea'))
    if ea is None:
        ea = etree.SubElement(rPr, qn('a:ea'))
    ea.set('typeface', '宋体')
    cs = rPr.find(qn('a:cs'))
    if cs is None:
        cs = etree.SubElement(rPr, qn('a:cs'))
    cs.set('typeface', '宋体')


def add_text(slide, x, y, w, h, text, size=10, color=NAVY, bold=False,
             align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP, line_spacing=1.12):
    box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
    tf = box.text_frame
    tf.word_wrap = True
    tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0
    tf.vertical_anchor = anchor
    for i, line in enumerate(str(text).split('\n')):
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.alignment = align
        p.line_spacing = line_spacing
        r = p.add_run()
        r.text = line
        set_run(r, size, color, bold)
    return box


def add_rect(slide, x, y, w, h, fill, line=None, radius=False):
    shp = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE if radius else MSO_SHAPE.RECTANGLE,
                                 Inches(x), Inches(y), Inches(w), Inches(h))
    shp.fill.solid(); shp.fill.fore_color.rgb = fill
    if line:
        shp.line.color.rgb = line; shp.line.width = Pt(0.75)
    else:
        shp.line.fill.background()
    if radius:
        try:
            shp.adjustments[0] = 0.08
        except Exception:
            pass
    return shp


def rate_color(rate):
    if rate >= 80:
        return GREEN
    if rate >= 60:
        return AMBER
    return RED


def add_table(slide, x, y, w, h, headers, rows, widths):
    nrows, ncols = len(rows) + 1, len(headers)
    table = slide.shapes.add_table(nrows, ncols, Inches(x), Inches(y), Inches(w), Inches(h)).table
    table.first_row = True
    table.horz_banding = False
    for j, wd in enumerate(widths):
        table.columns[j].width = Inches(wd)
    table.rows[0].height = Inches(0.42)
    for i in range(1, nrows):
        table.rows[i].height = Inches(0.68)

    for j, htext in enumerate(headers):
        cell = table.cell(0, j)
        cell.fill.solid(); cell.fill.fore_color.rgb = NAVY
        cell.margin_left = Inches(0.06); cell.margin_right = Inches(0.04)
        cell.margin_top = Inches(0.03); cell.margin_bottom = Inches(0.03)
        cell.vertical_anchor = MSO_ANCHOR.MIDDLE
        p = cell.text_frame.paragraphs[0]
        p.alignment = PP_ALIGN.CENTER if j in (0, 1, 2, 3) else PP_ALIGN.LEFT
        r = p.add_run(); r.text = htext
        set_run(r, 9.5, WHITE, True)

    for i, row in enumerate(rows, start=1):
        fill = PALE if i % 2 == 0 else WHITE
        for j, val in enumerate(row):
            cell = table.cell(i, j)
            cell.fill.solid(); cell.fill.fore_color.rgb = fill
            cell.margin_left = Inches(0.06); cell.margin_right = Inches(0.04)
            cell.margin_top = Inches(0.03); cell.margin_bottom = Inches(0.03)
            cell.vertical_anchor = MSO_ANCHOR.MIDDLE
            p = cell.text_frame.paragraphs[0]
            p.alignment = PP_ALIGN.CENTER if j in (0, 1, 2, 3) else PP_ALIGN.LEFT
            p.line_spacing = 1.05
            r = p.add_run(); r.text = str(val)
            color = NAVY
            bold = j == 0
            if j == 3:
                try:
                    color = rate_color(float(str(val).split('%')[0]))
                    bold = True
                except Exception:
                    pass
            set_run(r, 9.8, color, bold)
    return table


prs = Presentation(SRC)
blank = prs.slide_layouts[1]
s = prs.slides.add_slide(blank)
for shape in list(s.shapes):
    if shape.is_placeholder:
        shape._element.getparent().remove(shape._element)

# Header
add_rect(s, 0, 0, 13.333, 0.06, BLUE)
if os.path.exists(LOGO):
    s.shapes.add_picture(LOGO, Inches(0.48), Inches(0.22), height=Inches(0.34))
add_text(s, 0.48, 0.64, 11.0, 0.46, '六人年度目标责任书达成一览', size=20, color=NAVY, bold=True)
add_text(s, 0.48, 1.08, 12.3, 0.3,
         '销售目标 + 责任书关键维度｜2026年1-10月｜单位：万元',
         size=9.5, color=GREY)

rows = [
    ['刘新元\n部门合计', '6,650', '3,828.70', '57.6%\n2,821.30', '大客户 45.7%\n拓展 75.7%', '科研 7.4%', '—', '2026责任书\n挑战目标'],
    ['刘欣\n拓展团队', '3,400', '2,573.71', '75.7%\n826.29', 'KA 46/85\n（54.1%）', 'NGS 待补', '8/11=72.7%', 'NGS\n主观评价'],
    ['赵云浩\n个人', '1,350', '532.67', '39.5%\n817.33', 'Y1 丢 4/15', 'Z 47.2%\nD 125.5%', '—', '主观评价'],
    ['刘子研\n个人', '1,300', '675.81', '52.0%\n624.19', 'Y1 丢 5/11', 'Z 75.3%\nE 1/2', '—', '主观评价'],
    ['吴云\n浙江团队', '300', '28.50', '9.5%\n271.50', '课题组 42/320', '团队60% 0/4', '个人 2.1%', '主观/权重110%'],
    ['韩远怀\n广东团队', '300', '14.09', '4.7%\n285.91', '课题组 40/400', '团队60% 0/5', '个人 1.3%', '主观/权重110%'],
]
add_table(s, 0.48, 1.55, 12.4, 5.00,
          ['姓名/口径', '年度目标', '1-10月实际', '达成率/缺口', '客户维度', '增长/攻关', '团队/其他', '待补/风险'],
          rows, widths=[1.25, 0.95, 1.1, 1.1, 2.55, 2.05, 1.55, 1.85])

# note
add_rect(s, 0.48, 6.55, 12.4, 0.36, LIGHT, line=RGBColor(0xD4, 0xE2, 0xF4), radius=True)
add_text(s, 0.62, 6.63, 12.0, 0.2,
         '口径：刘新元=部门合计；刘欣=销售拓展部团队；吴云/韩远怀=区域团队；其余=个人。绿≥80%、黄60–80%、红<60%；“待补”为责任书未提供或系统无可靠口径。',
         size=7.4, color=GREY)

# footer
add_rect(s, 0.48, 7.02, 12.35, 0.012, RGBColor(0xD9, 0xE2, 0xEE))
add_text(s, 0.48, 7.10, 9.9, 0.22,
         '实际=KPI看板1-10月；开票额=ERP含税代理；Y1/Z/E口径见责任书页。',
         size=7.2, color=MIDGREY)
add_text(s, 10.55, 7.10, 2.25, 0.22, '守护生命健康，缔造美好生活', size=7.5, color=BLUE, bold=True, align=PP_ALIGN.RIGHT)

# move new slide from end to position 6 (after P5)
sldIdLst = prs.slides._sldIdLst
new_id = sldIdLst[-1]
sldIdLst.remove(new_id)
sldIdLst.insert(5, new_id)

prs.save(OUT)
print('saved', OUT)
print('slides', len(prs.slides))
