#!/usr/bin/env python3
"""Build Excel and HTML for the three-SPU, nine-SKU smart-canteen strategy."""

from __future__ import annotations

import argparse
import html
import json
import re
import shutil
import tempfile
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile

from openpyxl import Workbook
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
from openpyxl.utils import get_column_letter


NAVY="14354B"; ORANGE="F57C00"; GREEN="218C74"; BLUE="0B79B7"; RED="C0392B"; WHITE="FFFFFF"; BLACK="222222"; GRAY="E8EEF2"; LIGHT_ORANGE="FFF1DF"
THIN=Side(style="thin",color="CAD4DB")


def title(ws,text,subtitle,cols):
    ws.merge_cells(start_row=1,start_column=1,end_row=1,end_column=cols); ws.cell(1,1,text)
    ws.cell(1,1).fill=PatternFill("solid",fgColor=NAVY); ws.cell(1,1).font=Font(name="微软雅黑",size=18,bold=True,color=WHITE); ws.cell(1,1).alignment=Alignment(vertical="center"); ws.row_dimensions[1].height=34
    ws.merge_cells(start_row=2,start_column=1,end_row=2,end_column=cols); ws.cell(2,1,subtitle)
    ws.cell(2,1).fill=PatternFill("solid",fgColor=LIGHT_ORANGE); ws.cell(2,1).font=Font(name="微软雅黑",size=10,color=BLACK); ws.cell(2,1).alignment=Alignment(wrap_text=True,vertical="center"); ws.row_dimensions[2].height=32


def header(ws,row,values,fill=BLUE):
    for c,value in enumerate(values,1):
        cell=ws.cell(row,c,value); cell.fill=PatternFill("solid",fgColor=fill); cell.font=Font(name="微软雅黑",size=10,bold=True,color=WHITE); cell.alignment=Alignment(horizontal="center",vertical="center",wrap_text=True); cell.border=Border(top=THIN,bottom=THIN,left=THIN,right=THIN)
    ws.row_dimensions[row].height=30


def body(ws,first,last,cols):
    for row in ws.iter_rows(min_row=first,max_row=last,min_col=1,max_col=cols):
        for cell in row:
            cell.font=Font(name="微软雅黑",size=10,color=BLACK); cell.alignment=Alignment(vertical="center",wrap_text=True); cell.border=Border(top=THIN,bottom=THIN,left=THIN,right=THIN)


def widths(ws,values):
    for c,value in enumerate(values,1): ws.column_dimensions[get_column_letter(c)].width=value


def setup(ws,a3=False,portrait=False):
    ws.sheet_view.showGridLines=False; ws.page_setup.orientation="portrait" if portrait else "landscape"; ws.page_setup.paperSize=ws.PAPERSIZE_A3 if a3 else ws.PAPERSIZE_A4
    ws.page_setup.fitToWidth=1; ws.page_setup.fitToHeight=0; ws.sheet_properties.pageSetUpPr.fitToPage=True
    ws.page_margins.left=.25; ws.page_margins.right=.25; ws.page_margins.top=.45; ws.page_margins.bottom=.45
    ws.oddFooter.center.text="CPT｜内部战略评审稿｜目标、评分和漏斗必须用真实经营数据校准"; ws.oddFooter.center.size=8


def inject_cache(path,cache_maps):
    with ZipFile(path,"r") as src: members={name:src.read(name) for name in src.namelist()}
    for member,cells in cache_maps.items():
        xml=members[member].decode("utf-8")
        for ref,value in cells.items():
            text=str(int(value) if float(value).is_integer() else float(value))
            pattern=re.compile(rf'(<c r="{re.escape(ref)}"[^>]*>.*?<f>.*?</f><v>).*?(</v></c>)')
            xml,count=pattern.subn(rf'\g<1>{text}\g<2>',xml,count=1)
            if count!=1: raise RuntimeError(f"cache missing {member} {ref}")
        members[member]=xml.encode("utf-8")
    with tempfile.NamedTemporaryFile(suffix=".xlsx",delete=False,dir=Path(path).parent) as tmp: temp=Path(tmp.name)
    try:
        with ZipFile(temp,"w",ZIP_DEFLATED) as dst:
            for name,data in members.items(): dst.writestr(name,data)
        temp.replace(path)
    finally:
        if temp.exists(): temp.unlink()


def score(item): return item["market"]*.35+item["position"]*.30+item["finance"]*.20+item["delivery"]*.15


def build_excel(model,path):
    wb=Workbook(); ws=wb.active; ws.title="00-战略总览"
    title(ws,"智慧食堂三大SPU、九个SKU年度产品与销售战略",f"周期：{model['period']}。从一个SPU进入，90—180天内向第二、第三SPU扩单。",8)
    rows=[("一句话战略","营养结算负责获客和高频入口，智慧食安负责治理突破，进销存负责经营增购。"),("保底任务",model["floor_target_wan"]),("基准任务",model["base_target_wan"]),("冲刺任务",model["stretch_target_wan"]),("回款目标",model["collection_target_wan"]),("毛管道",model["pipeline_target_wan"]),("主项目胜单",model["primary_project_wins"]),("SKU订单线",model["sku_order_lines"]),("核心打法","250个目标账户、3倍管道、五支战斗编组、每项目跨SPU复盘"),("证据边界",model["note"])]
    r=4
    for label,value in rows:
        ws.cell(r,1,label); ws.merge_cells(start_row=r,start_column=2,end_row=r,end_column=8); ws.cell(r,2,value); ws.cell(r,1).fill=PatternFill("solid",fgColor=GRAY)
        for c in range(1,9): ws.cell(r,c).border=Border(top=THIN,bottom=THIN,left=THIN,right=THIN); ws.cell(r,c).font=Font(name="微软雅黑",size=10,bold=c==1); ws.cell(r,c).alignment=Alignment(wrap_text=True,vertical="center")
        if isinstance(value,(int,float)) and label!="主项目胜单" and label!="SKU订单线": ws.cell(r,2).number_format='0"万元"'; ws.cell(r,2).font=Font(name="微软雅黑",size=15,bold=True,color=ORANGE)
        r+=1
    widths(ws,[18,22,22,22,22,22,22,22]); setup(ws,portrait=True)

    pws=wb.create_sheet("01-三SPU布局")
    title(pws,"三条产品线战略分工","产品线必须是可承担收入、客户和资源责任的业务单元，不是功能目录。",8)
    header(pws,4,["序号","SPU","战略角色","年度目标(万元)","目标占比","产品线任务","主战场","资源动作"],fill=GREEN)
    spu_cache={}
    for r,item in enumerate(model["spus"],5):
        vals=[item["sequence"],item["name"],item["role"],None,item["share"],item["mission"],item["battle"],"聚焦标准包、案例、报价、交付和跨SPU增购"]
        for c,v in enumerate(vals,1): pws.cell(r,c,v)
        pws.cell(r,4,f'=SUMIF(\'05-年度销售任务\'!$B:$B,B{r},\'05-年度销售任务\'!$H:$H)'); spu_cache[f"D{r}"]=item["target_wan"]; pws.cell(r,5).number_format="0%"; pws.row_dimensions[r].height=72
    body(pws,5,7,8); widths(pws,[7,18,20,17,13,48,48,42]); setup(pws,a3=True)

    mws=wb.create_sheet("02-九SKU产品地图")
    title(mws,"九个销售SKU产品地图","基础负责进入，标准负责主战，专业负责升级和高客单；不能九个SKU平均用力。",10)
    header(mws,4,["序号","SPU","SKU名称","档位","战略角色","购买人","客户购买理由","目标(万元)","产品动作","证据"],fill=ORANGE)
    for r,item in enumerate(model["skus"],5):
        vals=[item["sequence"],item["spu"],item["name"],item["tier"],item["role"],item["buyer"],item["wedge"],item["target_wan"],item["action"],"A/B能力；D目标"]
        for c,v in enumerate(vals,1): mws.cell(r,c,v)
        mws.row_dimensions[r].height=64
    body(mws,5,13,10); widths(mws,[7,16,25,10,16,38,48,15,52,18]); mws.freeze_panes="A5"; mws.auto_filter.ref="A4:J13"; setup(mws,a3=True)

    sws=wb.create_sheet("03-SPAN-PDC")
    title(sws,"九SKU SPAN/PDC初始评分","市场吸引力35%、竞争地位30%、财务潜力20%、交付复用15%；分数全部为D级假设。",11)
    header(sws,4,["序号","SPU","SKU","角色","市场吸引力","竞争地位","财务潜力","交付复用","加权分","排序","关键动作"])
    score_cache={}; ranking=sorted([(score(x),x["name"]) for x in model["skus"]],reverse=True); ranks={name:i+1 for i,(_,name) in enumerate(ranking)}
    for r,item in enumerate(model["skus"],5):
        vals=[item["sequence"],item["spu"],item["name"],item["role"],item["market"],item["position"],item["finance"],item["delivery"],None,ranks[item["name"]],item["action"]]
        for c,v in enumerate(vals,1): sws.cell(r,c,v)
        sws.cell(r,9,f"=E{r}*35%+F{r}*30%+G{r}*20%+H{r}*15%"); score_cache[f"I{r}"]=score(item); sws.cell(r,9).number_format="0.00"; sws.row_dimensions[r].height=56
    body(sws,5,13,11); widths(sws,[7,16,25,16,13,13,13,13,13,9,52]); setup(sws,a3=True)

    rws=wb.create_sheet("04-7-2-1资源配置")
    title(rws,"九SKU 7-2-1资源配置","7-2-1表示资源优先级；销售、研发、渠道和交付可使用不同的实际比例。",8)
    header(rws,4,["类别","SKU","目标(万元)","资源动作","市场打法","升级条件","降级/停止条件","管理节奏"],fill=GREEN)
    groups=[("聚焦","智能结算基础、营养结算标准、单/多食堂食安、单食堂进销存",800,"主资源投入标准化和区域复制","营养结算获客，食安/进销存增购","连续复制、毛利回款达标","非标侵蚀、低价无毛利","月度"),("突破","营养健康专业、集团食安、多食堂进销存",340,"每个方向先给1个付费样板","从已有客户向上升级或伙伴进入","同包3个付费客户","无付费方、无复制、交付失控","季度"),("布局","集团采购与库存",60,"只给一个付费样板名额","集团预算、主数据和ERP边界明确才做","可控交付和高客单验证","两个季度无样板则降级","季度")]
    for r,vals in enumerate(groups,5):
        for c,v in enumerate(vals,1): rws.cell(r,c,v)
        rws.row_dimensions[r].height=78
    body(rws,5,7,8); widths(rws,[13,48,16,42,42,36,40,13]); setup(rws,a3=True)

    aws=wb.create_sheet("05-年度销售任务")
    title(aws,"九SKU年度销售任务分解","基准签约1200万元；同一项目可以包含多条SKU订单线，不能把33条订单线误当33个独立客户。",10)
    header(aws,4,["序号","SPU","SKU","角色","目标单量","规划客单价(万元)","计算目标","签约目标(万元)","占比","说明"],fill=ORANGE)
    sales_cache={}
    for r,item in enumerate(model["skus"],5):
        vals=[item["sequence"],item["spu"],item["name"],item["role"],item["units"],item["asp_wan"],None,item["target_wan"],None,item["action"]]
        for c,v in enumerate(vals,1): aws.cell(r,c,v)
        aws.cell(r,7,f"=E{r}*F{r}"); aws.cell(r,9,f"=H{r}/$H$14"); sales_cache[f"G{r}"]=item["target_wan"]; sales_cache[f"I{r}"]=item["target_wan"]/model["base_target_wan"]; aws.cell(r,9).number_format="0.0%"; aws.row_dimensions[r].height=52
    aws.cell(14,1,"合计"); aws.merge_cells("A14:G14"); aws.cell(14,8,"=SUM(H5:H13)"); aws.cell(14,9,"=SUM(I5:I13)"); sales_cache["H14"]=model["base_target_wan"]; sales_cache["I14"]=1
    body(aws,5,14,10); widths(aws,[7,16,25,16,11,18,15,18,11,50]); aws.freeze_panes="A5"; setup(aws,a3=True)

    fws=wb.create_sheet("06-销售漏斗")
    title(fws,"1200万元基准情景销售漏斗","保持3倍毛管道；阶段概率是冷启动假设，每月用赢单、失单和延期回写。",6)
    header(fws,4,["阶段","目标数量","阶段转化率","阶段门禁","跨SPU动作","停止条件"])
    for r,item in enumerate(model["funnel"],5):
        vals=[item["stage"],item["count"],item["conversion"],item["gate"],"明确首选SPU和第二SPU增购路径","缺付费方、范围或下一步不得升级"]
        for c,v in enumerate(vals,1): fws.cell(r,c,v)
        fws.cell(r,3).number_format="0%"; fws.row_dimensions[r].height=58
    body(fws,5,10,6); widths(fws,[20,14,16,52,42,42]); setup(fws,a3=True)

    bws=wb.create_sheet("07-五支战斗编组")
    title(bws,"三SPU五支市场战斗编组","不一上来卖三套系统；从最急的一条SPU进入，再设计第二、第三SPU扩单。",7)
    header(bws,4,["战斗编组","入口SKU","扩单组合","购买委员会","客户买点","进入路径","禁止打法"],fill=ORANGE)
    forbids=["不把三SPU打包强卖","不把集团版当无限组织","没有总部预算不报价","没有伙伴不做区域重交付","不把健康服务做成一次报告"]
    for r,(item,forbid) in enumerate(zip(model["battle_formations"],forbids),5):
        vals=[item["name"],item["entry"],item["expand"],item["buyer"],item["win"],"先诊断—演示—配置—报价—验收",forbid]
        for c,v in enumerate(vals,1): bws.cell(r,c,v)
        bws.row_dimensions[r].height=78
    body(bws,5,9,7); widths(bws,[30,30,46,38,48,38,38]); setup(bws,a3=True)

    qws=wb.create_sheet("08-季度战役")
    title(qws,"未来12个月季度战役","Q1建制、Q2扩单、Q3复制、Q4整包和续费；每季度重做SPAN/PDC。",6)
    header(qws,4,["阶段","签约目标(万元)","胜单","战役主题","关键动作","通过门槛"],fill=GREEN)
    for r,item in enumerate(model["quarters"],5):
        vals=[item["period"],item["target_wan"],item["wins"],item["theme"],item["action"],"签约、回款、跨SPU增购和交付同时达标"]
        for c,v in enumerate(vals,1): qws.cell(r,c,v)
        qws.row_dimensions[r].height=72
    qws.cell(9,1,"年度合计"); qws.cell(9,2,"=SUM(B5:B8)"); qws.cell(9,3,"=SUM(C5:C8)"); quarter_cache={"B9":model["base_target_wan"],"C9":model["primary_project_wins"]}
    body(qws,5,9,6); widths(qws,[20,18,12,22,70,44]); setup(qws,a3=True)

    cws=wb.create_sheet("09-跨SPU扩单")
    title(cws,"Land and Expand｜从一个SPU进入，再向两条产品线扩单","每个项目验收后30—90天必须做一次跨SPU经营复盘。",6)
    header(cws,4,["客户最急问题","首选SPU","首次交付结果","第二SPU机会","第三SPU机会","复盘问题"],fill=ORANGE)
    cross=[("钱、补贴、排队和体验","营养结算","消费和对账稳定","食安台账、AI监管和整改","采购、库存与成本","食堂是否还在手工做食安或库存？"),("责任、风险、台账和监管","智慧食安","风险与整改闭环","人员消费、营养菜单和健康服务","采购验收与批次追溯","监管数据是否能反推经营改进？"),("采购、库存、损耗和成本","智慧进销存","采购库存可追溯","消费销量与营养菜品","食安验收和供应商风险","采购数据能否与销售和食安联动？"),("集团统一治理","最明确预算SPU","总部与站点责任清楚","第二条业务线纳管","第三条业务线纳管","是否具备统一主数据、权限和ERP边界？"),("健康食堂建设","营养健康专业版","健康测评与营养服务","食安证明餐食可信","进销存证明食材与成本可追溯","客户是否愿意为持续运营而不是设备付费？")]
    for r,vals in enumerate(cross,5):
        for c,v in enumerate(vals,1): cws.cell(r,c,v)
        cws.row_dimensions[r].height=72
    body(cws,5,9,6); widths(cws,[34,22,40,42,42,52]); setup(cws,a3=True)

    kws=wb.create_sheet("10-KPI与缺口")
    title(kws,"经营KPI、商业门与证据缺口","不能只看签约额；毛利、回款、复用、跨SPU增购、交付和持续收入必须同时成立。",6)
    header(kws,4,["维度","指标/缺口","基准目标","当前证据","纠偏动作","停止线"],fill=RED)
    kpis=[("销售","签约/回款","1200万/950万","D级目标","月度按季度节奏复盘","低价无毛利或回款失控"),("管道","毛管道覆盖","≥3倍，即3600万","冷启动假设","低于1.5倍补账户和线索","无客户/金额/阶段不进预测"),("扩单","SKU订单线/主项目","33/24=1.38","D级目标","验收后30—90天跨SPU复盘","只卖一次性单点"),("产品","标准+配置占比","先建基线，逐季提高","缺数据","强制标准/配置/接口/非标分类","同类需求仍需新分支"),("交付","标准项目周期","内部目标≤30天","现有中位24天样本","记录人天、延期和售后","交付产能成为SOM上限"),("财务","9SKU成本和毛利","待补","缺成本/回款","按软件硬件实施售后拆分","无毛利红线不扩张"),("突破","专业/集团/多食堂进销存","每方向1个付费样板","B/D","同包3客户后加码","无付费方或交付失控"),("布局","集团采购与库存","两个季度1个可控样板","D","锁主数据、ERP和集团预算","两季无样板即降级"),("区域","京津冀/长三角样板","每区3个可引用项目","B/D","集中案例和渠道资源","连续两季无有效商机换区"),("持续收入","云/维保/营养服务","至少3次续费/增购/扩站点","缺数据","合同明确持续服务","不能证明持续收入不称第二曲线")]
    for r,vals in enumerate(kpis,5):
        for c,v in enumerate(vals,1): kws.cell(r,c,v)
        kws.row_dimensions[r].height=62
    body(kws,5,14,6); widths(kws,[14,34,32,34,44,44]); setup(kws,a3=True)

    wb.calculation.calcMode="auto"; wb.calculation.fullCalcOnLoad=True; wb.calculation.forceFullCalc=True; wb.properties.title="智慧食堂三大SPU九SKU年度产品与销售战略"; wb.properties.creator="康比特数字体育科技"
    path.parent.mkdir(parents=True,exist_ok=True); wb.save(path)
    inject_cache(path,{"xl/worksheets/sheet2.xml":spu_cache,"xl/worksheets/sheet4.xml":score_cache,"xl/worksheets/sheet6.xml":sales_cache,"xl/worksheets/sheet9.xml":quarter_cache})


def build_html(model,path):
    spu_cards="".join(f'<article class="spu"><span>{x["role"]}</span><h2>{x["sequence"]} · {x["name"]}</h2><b>{x["target_wan"]}万元</b><p>{x["mission"]}</p><small>{x["battle"]}</small></article>' for x in model["spus"])
    sku_cards="".join(f'<article class="sku"><span>{x["role"]}</span><h3>{x["spu"]}<br>{x["name"]}</h3><b>{x["target_wan"]}万元</b><p>{x["wedge"]}</p></article>' for x in model["skus"])
    battles="".join(f'<article class="battle"><h3>{x["name"]}</h3><p><b>入口：</b>{x["entry"]}</p><p><b>扩单：</b>{x["expand"]}</p><p><b>为什么赢：</b>{x["win"]}</p></article>' for x in model["battle_formations"])
    quarters="".join(f'<tr><td>{x["period"]}</td><td>{x["target_wan"]}万元</td><td>{x["wins"]}个</td><td>{x["theme"]}</td><td>{x["action"]}</td></tr>' for x in model["quarters"])
    page=f"""<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>智慧食堂三大SPU九SKU年度战略</title><style>:root{{--o:#f57c00;--n:#14354b;--p:#fffaf2;--i:#26343d}}*{{box-sizing:border-box}}body{{margin:0;background:var(--p);color:var(--i);font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;line-height:1.65}}header{{padding:64px 6vw 52px;background:linear-gradient(135deg,#ff8500,#ffb22e);color:#fff}}h1{{font-size:48px;line-height:1.12;margin:12px 0}}header p{{font-size:19px;max-width:920px}}.metrics,.grid3{{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}}.metrics{{margin-top:30px}}.metric{{background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.45);padding:18px;border-radius:16px}}.metric b{{display:block;font-size:28px}}main{{width:min(1240px,92vw);margin:auto;padding:42px 0 80px}}section{{margin:42px 0}}h2{{color:var(--n)}}.decision{{background:#fff;border-left:7px solid var(--o);border-radius:0 18px 18px 0;padding:26px;font-size:21px;box-shadow:0 8px 30px rgba(80,45,0,.08)}}.spu,.sku,.battle{{background:#fff;border:1px solid #ffdaa1;border-radius:18px;padding:20px;box-shadow:0 7px 24px rgba(90,50,0,.06)}}.spu span,.sku span{{background:#fff0d5;color:#a95500;padding:4px 9px;border-radius:999px;font-size:13px}}.spu b,.sku b{{font-size:26px;color:var(--o)}}.spu small,.sku p,.battle p{{color:#53646d}}table{{width:100%;border-collapse:collapse;background:#fff}}th{{background:var(--n);color:#fff}}th,td{{padding:14px;border-bottom:1px solid #dce5ea;text-align:left;vertical-align:top}}.war{{background:var(--n);color:#fff;border-radius:22px;padding:30px}}.war h2{{color:#fff}}.war ol{{columns:2;column-gap:50px}}footer{{background:#1d2d37;color:#dce5ea;padding:28px 6vw}}@media(max-width:850px){{.metrics,.grid3{{grid-template-columns:1fr}}h1{{font-size:36px}}.war ol{{columns:1}}}}</style></head><body><header><small>CPT · PRODUCT STRATEGY</small><h1>三大SPU，九个SKU<br>从单点成交走向组合经营</h1><p>营养结算负责获客与高频入口，智慧食安负责治理突破，智慧进销存负责经营增购。从客户最急的一条SPU进入，再在90—180天内向第二、第三SPU扩单。</p><div class="metrics"><div class="metric"><b>{model['base_target_wan']}万元</b>基准签约</div><div class="metric"><b>{model['pipeline_target_wan']}万元</b>毛管道</div><div class="metric"><b>{model['primary_project_wins']}个 / {model['sku_order_lines']}条</b>主项目 / SKU订单线</div></div></header><main><section><div class="decision">不与头部厂商拼“大而全”。用营养结算拿下日常入口，用食安和进销存扩展治理与经营深度，用营养健康专业版建立康比特差异化。</div></section><section><h2>三条产品线的战场分工</h2><div class="grid3">{spu_cards}</div></section><section><h2>九个SKU年度任务</h2><div class="grid3">{sku_cards}</div></section><section><h2>五支战斗编组</h2><div class="grid3">{battles}</div></section><section><h2>季度战役</h2><table><thead><tr><th>阶段</th><th>签约</th><th>胜单</th><th>主题</th><th>关键动作</th></tr></thead><tbody>{quarters}</tbody></table></section><section class="war"><h2>怎么打</h2><ol><li>250个实名目标账户，不做泛流量。</li><li>保持3倍管道，低于1.5倍立即补线索。</li><li>客户先从钱、责任或成本三类问题选择入口SPU。</li><li>验收后30—90天必须做跨SPU复盘。</li><li>24个主项目要形成33条SKU订单线。</li><li>京津冀和长三角分别形成3个样板。</li><li>突破SKU先拿付费样板，同包3客户后加码。</li><li>集团进销存两个季度无样板即降级。</li></ol></section><section><h2>三档任务</h2><table><tr><th>保底</th><th>基准</th><th>冲刺</th></tr><tr><td>{model['floor_target_wan']}万元</td><td>{model['base_target_wan']}万元</td><td>{model['stretch_target_wan']}万元</td></tr></table><p>{model['note']}</p></section></main><footer>内部评审稿｜正式年度任务需销售、财务、产品、交付和管理层共同确认。</footer></body></html>"""
    path.write_text(page,encoding="utf-8")


def main():
    parser=argparse.ArgumentParser(); parser.add_argument("--workdir",type=Path,required=True); parser.add_argument("--output",type=Path,required=True); args=parser.parse_args()
    model=json.loads((args.workdir/"strategy-model.json").read_text(encoding="utf-8")); final=args.output/"01-最终交付"; evidence=args.output/"02-内部证据"; final.mkdir(parents=True,exist_ok=True); evidence.mkdir(parents=True,exist_ok=True)
    shutil.copy2(args.workdir/"SMART_CANTEEN_3_SPU_9_SKU_STRATEGY.md",final/"智慧食堂三大SPU九SKU年度产品与销售战略.md"); shutil.copy2(args.workdir/"strategy-model.json",evidence/"strategy-model.json"); shutil.copy2(args.workdir/"source-index.csv",evidence/"source-index.csv"); shutil.copy2(args.workdir/"ROUTING_NOTE.md",evidence/"ROUTING_NOTE.md")
    build_excel(model,final/"智慧食堂三大SPU九SKU年度产品与销售战略.xlsx"); build_html(model,final/"smart-canteen-3-spu-9-sku-annual-strategy.html")
    print(json.dumps({"status":"PASS","spus":3,"skus":9,"target_wan":model["base_target_wan"],"output":str(args.output)},ensure_ascii=False))


if __name__=="__main__": main()
