from __future__ import annotations

import argparse
import re
import tempfile
import xml.etree.ElementTree as ET
from pathlib import Path
from zipfile import ZipFile


SLIDE_PART_RE = re.compile(r"ppt/slides/slide\d+\.xml$")
PLACEHOLDER_RE = re.compile(r"\{\{([^{}]+)\}\}")

OOXML_NS = {
    "a": "http://schemas.openxmlformats.org/drawingml/2006/main",
    "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
    "r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
}

for _prefix, _uri in OOXML_NS.items():
    ET.register_namespace(_prefix, _uri)


class PlaceholderFillError(ValueError):
    """Raised when the deck contains a placeholder without a mapped analysis."""


ANALYSIS_REPLACEMENTS: dict[str, str] = {
    "战客属地累计招标金额75亿元、招标次数1532次、金额同比+119.54%；请基于数据进行概括总结分析，凸显数据特征": (
        "战客75亿元居区域首位，金额同比翻倍增长，市级重点客户与跨区项目拉动最强。"
    ),
    "浦东属地累计招标金额49.81亿元、招标次数977次、金额同比+195.91%；请基于数据进行概括总结分析，凸显数据特征": (
        "浦东49.81亿元、同比+195.91%，核心功能区投资和数字化项目持续释放。"
    ),
    "党政行业累计招标金额63.33亿元、招标次数1149次、金额同比+67.76%；请基于数据进行概括总结分析，凸显数据特征": (
        "党政63.33亿元居行业首位，政务治理、数字政府和公共服务仍是需求基本盘。"
    ),
    "交通行业累计招标金额35.99亿元、招标次数371次、金额同比+390.1%；请基于数据进行概括总结分析，凸显数据特征": (
        "交通35.99亿元、同比+390.1%，枢纽建设、道路运维和智慧交通需求快速升温。"
    ),
    "上海市道路运输事业发展中心累计招标预算105378.19万元、招标次数7次；请基于数据进行概括总结分析，凸显数据特征": (
        "道路运输事业发展中心预算10.54亿元，交通基础设施及运维升级带动显著。"
    ),
    "上海市大数据中心累计招标预算98185.766万元、招标次数98次；请基于数据进行概括总结分析，凸显数据特征": (
        "大数据中心预算9.82亿元、98次，政务云、数据底座和一网通办支撑需求活跃。"
    ),
    "规划要点,此处最后由智能体修订": (
        "“十五五”服务业突出数智化、标准化、融合化、国际化，生产性服务业和数据要素服务将持续放大。"
    ),
    "政策导向,此处最后由智能体修订": (
        "公开政策聚焦服务业扩能提质、城市数字化转型和“人工智能+”，政企云、数据底座、智慧交通/医疗将持续释放项目需求。"
    ),
    "累计金额Top3行业为党政63.33亿元、交通35.99亿元、农业文旅34.51亿元，合计金额133.83亿元、占比53.3%；请基于数据进行概括总结分析，凸显数据特征": (
        "党政、交通、农业文旅合计占比53.3%，公共治理、交通基建与文旅农旅成为上半年主线。"
    ),
    "党政行业累计招标金额63.33亿元、招标次数1149次、个数同比-17.58%、金额同比+67.76%；请基于数据进行概括总结分析，凸显数据特征": (
        "党政金额居首，次数回落但金额增67.76%，单项目规模提升，数字政府和治理类项目支撑明显。"
    ),
    "交通行业累计招标金额35.99亿元、招标次数371次、个数同比+24.08%、金额同比+390.1%；请基于数据进行概括总结分析，凸显数据特征": (
        "交通金额增近4倍且次数同步增长，枢纽交通、道路运维与智慧出行项目集中释放。"
    ),
    "农业文旅行业累计招标金额34.51亿元、招标次数291次、个数同比+18.29%、金额同比+395.02%；请基于数据进行概括总结分析，凸显数据特征": (
        "农业文旅34.51亿元、同比+395.02%，文旅融合、乡村场景和公共服务更新热度升温。"
    ),
    "工业能源行业累计招标金额20.55亿元、招标次数627次、个数同比+43.15%、金额同比+689.87%；请基于数据进行概括总结分析，凸显数据特征": (
        "工业能源次数、金额双升，金额增幅最高，能源改造、设备更新和工业服务大单拉动显著。"
    ),
    "融合创新行业累计招标金额20.50亿元、招标次数312次、个数同比+149.6%、金额同比+666.63%；请基于数据进行概括总结分析，凸显数据特征": (
        "融合创新次数同比+149.6%、金额+666.63%，新技术融合应用正从试点走向规模化采购。"
    ),
    "商客行业累计招标金额20.34亿元、招标次数241次、个数同比-13.93%、金额同比+285.32%；请基于数据进行概括总结分析，凸显数据特征": (
        "商客次数回落但金额大增，客户需求向少量大额、综合解决方案型项目集中。"
    ),
    "教育行业累计招标金额17.92亿元、招标次数434次、个数同比-30%、金额同比+75.96%；请基于数据进行概括总结分析，凸显数据特征": (
        "教育项目数下降30%但金额增长75.96%，校级信息化和基础设施更新仍有大单支撑。"
    ),
    "医卫行业累计招标金额17.32亿元、招标次数350次、个数同比-37.94%、金额同比+79.59%；请基于数据进行概括总结分析，凸显数据特征": (
        "医卫次数降幅较大、金额仍增79.59%，医院扩建、智慧医院和设备更新抬升单体金额。"
    ),
    "金融行业累计招标金额16.04亿元、招标次数902次、个数同比+30.72%、金额同比+54.69%；请基于数据进行概括总结分析，凸显数据特征": (
        "金融次数、金额同步增长，网络安全、基础设施和核心系统升级需求保持韧性。"
    ),
    "互联网行业累计招标金额4.65亿元、招标次数143次、个数同比-1.38%、金额同比+45.19%；请基于数据进行概括总结分析，凸显数据特征": (
        "互联网规模较小但金额仍增，采购更偏平台能力、云资源和运营服务等结构性需求。"
    ),
    "累计金额Top3属地为战客75.00亿元、浦东49.81亿元、闵行19.09亿元，合计金额143.90亿元、占比56.4%；请基于数据进行概括总结分析，凸显数据特征": (
        "战客、浦东、闵行合计占比56.4%，属地贡献头部集中，市级客户和核心功能区拉动明显。"
    ),
    "战客属地累计招标金额75.00亿元、招标次数1532次、个数同比+16.95%、金额同比+119.54%；请基于数据进行概括总结分析，凸显数据特征": (
        "战客75.00亿元居首，次数和金额双增，市级重点客户及跨区项目仍是最大增量来源。"
    ),
    "浦东属地累计招标金额49.81亿元、招标次数977次、个数同比+22.28%、金额同比+195.91%；请基于数据进行概括总结分析，凸显数据特征": (
        "浦东49.81亿元、金额同比近翻两倍，功能区投资和数字化项目持续外溢。"
    ),
    "闵行属地累计招标金额19.09亿元、招标次数302次、个数同比+1.68%、金额同比+242.13%；请基于数据进行概括总结分析，凸显数据特征": (
        "闵行19.09亿元、同比+242.13%，次数基本持平，增长主要来自项目单体规模放大。"
    ),
    "其他属地累计招标金额15.27亿元、招标次数103次、个数同比-43.72%、金额同比+1034.41%；请基于数据进行概括总结分析，凸显数据特征": (
        "其他属地次数下降但金额大幅跃升，少数大额项目对当期规模贡献突出。"
    ),
    "崇明属地累计招标金额15.17亿元、招标次数157次、个数同比+153.23%、金额同比+623.68%；请基于数据进行概括总结分析，凸显数据特征": (
        "崇明次数、金额均高增，生态文旅、交通和公共服务补短板形成阶段性放量。"
    ),
    "南区属地累计招标金额14.35亿元、招标次数417次、个数同比-22.78%、金额同比+65.68%；请基于数据进行概括总结分析，凸显数据特征": (
        "南区金额增长但次数下降，需求结构向中大型项目集中，需关注重点客户深挖。"
    ),
    "宝山属地累计招标金额10.92亿元、招标次数173次、个数同比+24.46%、金额同比+447.61%；请基于数据进行概括总结分析，凸显数据特征": (
        "宝山10.92亿元、金额同比+447.61%，工业转型、城市更新和公共设施项目带动明显。"
    ),
    "北区属地累计招标金额10.84亿元、招标次数260次、个数同比-25.71%、金额同比+35.99%；请基于数据进行概括总结分析，凸显数据特征": (
        "北区次数回落但金额小幅增长，存量区域以项目质量提升对冲数量下滑。"
    ),
    "松江属地累计招标金额10.67亿元、招标次数259次、个数同比+30.81%、金额同比+356.75%；请基于数据进行概括总结分析，凸显数据特征": (
        "松江次数、金额同步增长，制造服务、专业服务和新城建设需求延续。"
    ),
    "奉贤属地累计招标金额10.28亿元、招标次数118次、个数同比-7.81%、金额同比+153.92%；请基于数据进行概括总结分析，凸显数据特征": (
        "奉贤次数小幅下降但金额大增，医院扩建等大额民生项目带动明显。"
    ),
    "西区属地累计招标金额9.44亿元、招标次数385次、个数同比-12.7%、金额同比+57.59%；请基于数据进行概括总结分析，凸显数据特征": (
        "西区次数下降、金额上升，客户需求由零散采购转向集约化综合项目。"
    ),
    "青浦属地累计招标金额8.32亿元、招标次数114次、个数同比-21.38%、金额同比+237.18%；请基于数据进行概括总结分析，凸显数据特征": (
        "青浦金额同比+237.18%，长三角示范区和会展物流相关需求具备支撑。"
    ),
    "金山属地累计招标金额3.41亿元、招标次数52次、个数同比-59.06%、金额同比+323.9%；请基于数据进行概括总结分析，凸显数据特征": (
        "金山项目数量明显回落但金额增长，少量能源和产业项目贡献拉动。"
    ),
    "嘉定属地累计招标金额2.60亿元、招标次数94次、个数同比-7.84%、金额同比+31.03%；请基于数据进行概括总结分析，凸显数据特征": (
        "嘉定规模较小但保持正增长，汽车产业链和城市服务类需求仍需持续跟踪。"
    ),
    "互拓属地累计招标金额0.03亿元、招标次数10次；请基于数据进行概括总结分析，凸显数据特征": (
        "互拓金额基数较低，当前以机会培育和跨域协同跟进为主。"
    ),
    "2026年5月：1138次/73.66亿、个数/金额环比-6.26%/+8.08%；请基于数据进行概括总结分析，凸显数据特征": (
        "5月招标1138次、73.66亿元，次数小幅回落但金额环比+8.08%，由大额项目拉动。"
    ),
    "行业Top3：交通22.44/党政10.66/工业能源9.34亿，合计42.44亿/58.2%；请基于数据进行概括总结分析，凸显数据特征": (
        "交通、党政、工业能源合计58.2%，行业集中度高，基建交通与工业能源成为增量主轴。"
    ),
    "交通：61次/22.44亿、个数/金额环比-29.07%/+241.57%；请基于数据进行概括总结分析，凸显数据特征": (
        "交通金额环比+241.57%但次数下降，少数大额交通项目集中落地。"
    ),
    "党政：258次/10.66亿、个数/金额环比-5.15%/-4.92%；请基于数据进行概括总结分析，凸显数据特征": (
        "党政次数和金额均小幅回落，但258次仍居高位，政务类刚性采购保持稳定。"
    ),
    "工业能源：122次/9.34亿、个数/金额环比-15.28%/+153.5%；请基于数据进行概括总结分析，凸显数据特征": (
        "工业能源金额环比+153.5%，设备更新、能源改造和工业服务项目放量明显。"
    ),
    "属地Top3：战客20.83/浦东13.58/崇明8.93亿，合计43.34亿/58.8%；请基于数据进行概括总结分析，凸显数据特征": (
        "战客、浦东、崇明合计58.8%，单月区域集中度与大额项目依赖度同步提高。"
    ),
    "战客：298次/20.83亿、个数/金额环比-19.02%/-6.26%；请基于数据进行概括总结分析，凸显数据特征": (
        "战客金额环比微降但仍达20.83亿元，头部客户基本盘稳固。"
    ),
    "浦东：272次/13.58亿、个数/金额环比+8.37%/+29.44%；请基于数据进行概括总结分析，凸显数据特征": (
        "浦东次数和金额双升，核心产业区项目节奏较快，是单月增量的重要来源。"
    ),
    "崇明：37次/8.93亿、个数/金额环比-30.19%/+375.77%；请基于数据进行概括总结分析，凸显数据特征": (
        "崇明金额环比+375.77%，低次数高金额特征突出，阶段性大项目贡献明显。"
    ),
    "2026年5月：139客户348次/20.66亿；请基于数据进行概括总结分析，凸显数据特征": (
        "5月139客户348次、20.66亿元，医疗、交通、政务数字底座等公共服务场景集中释放。"
    ),
    "139重点项目Top5见右表，最高38288.00万元；请基于项目名称概括重点项目共性内容": (
        "集中在医院扩建、东方枢纽配套道路、基础云平台及金融IT设备，体现民生基建和数字底座两条主线"
    ),
    "行业Top3：商客27.38/党政13.81/医卫3.12亿，占比89.2%": (
        "商客、党政、医卫贡献89.2%，运营商中标集中在政企和公共服务场景。"
    ),
    "商客：27.38亿，联通80.1%": (
        "商客27.38亿元，联通金额占80.1%，大额项目优势突出。"
    ),
    "党政：13.81亿，电信51.1%": (
        "党政13.81亿元，电信金额占51.1%，政务场景竞争相对均衡。"
    ),
    "医卫：3.12亿，电信66.2%": (
        "医卫3.12亿元，电信金额占66.2%，医疗信息化优势明显。"
    ),
    "区域Top3：战客中心37.45/浦东2.75/闵行1.38亿，占比84.3%": (
        "战客中心、浦东、闵行合计84.3%，运营商机会高度集中。"
    ),
    "战客中心：37.45亿，联通67.0%": (
        "战客中心37.45亿元，联通占67.0%，头部客户大单拉动。"
    ),
    "浦东：2.75亿，移动84.7%": (
        "浦东2.75亿元，移动占84.7%，核心区域单点优势明显。"
    ),
    "闵行：1.38亿，电信53.6%": (
        "闵行1.38亿元，电信占53.6%，份额领先但仍有竞争空间。"
    ),
    "2026年1-5月：累计458个/49.66亿，同项+16.24%、额-10.01%；请概括，凸显特征": (
        "累计项目数增16.24%但金额降10.01%，中小项目增多，大额项目节奏偏后。"
    ),
    "移动累计：112个/7.44亿，15.0%": (
        "移动112个/7.44亿元，占15.0%，项目覆盖有基础但金额份额偏低。"
    ),
    "电信累计：217个/14.43亿，29.1%": (
        "电信217个/14.43亿元，占29.1%，项目数优势显著，金额居中。"
    ),
    "联通累计：129个/27.79亿，56.0%": (
        "联通129个/27.79亿元，占56.0%，依靠大额项目取得金额领先。"
    ),
    "2026年5月：单月121个/26.05亿，环项+16.35%、额+166.17%；请概括，凸显特征": (
        "5月金额环比+166.17%、项目数+16.35%，单月由大额项目强拉动。"
    ),
    "移动单月：27个/0.55亿，2.1%": (
        "移动27个/0.55亿元，占2.1%，单月金额贡献偏弱。"
    ),
    "电信单月：57个/1.69亿，6.5%": (
        "电信57个/1.69亿元，占6.5%，项目活跃但大额不足。"
    ),
    "联通单月：37个/23.82亿，91.4%": (
        "联通37个/23.82亿元，占91.4%，单月几乎由联通大单主导。"
    ),
    "行业Top3：商客27.38/党政13.81/医卫3.12亿，占比89.2%；请基于数据进行概括总结分析，凸显数据特征": (
        "商客、党政、医卫合计占89.2%，行业中标强集中，竞争焦点落在政企和民生服务场景。"
    ),
    "商客行业：27.38亿，个数电信41.9%，金额联通80.1%；请基于数据进行概括总结分析，凸显数据特征": (
        "商客27.38亿元，电信项目数占41.9%但联通金额占80.1%，联通拿下少数大额项目。"
    ),
    "党政行业：13.81亿，个数电信55.0%，金额电信51.1%；请基于数据进行概括总结分析，凸显数据特征": (
        "党政13.81亿元，电信在项目数和金额均过半，政务客户粘性和交付能力形成优势。"
    ),
    "医卫行业：3.12亿，个数电信64.0%，金额电信66.2%；请基于数据进行概括总结分析，凸显数据特征": (
        "医卫3.12亿元，电信项目数和金额均领先，医院信息化和网络安全项目适配度较高。"
    ),
    "属地Top3：战客中心37.45/浦东2.75/闵行1.38亿，占比84.3%；请基于数据进行概括总结分析，凸显数据特征": (
        "战客中心、浦东、闵行合计84.3%，区域中标高度头部化，资源应优先投向战客及核心城区。"
    ),
    "战客中心：37.45亿，个数电信56.7%，金额联通67.0%；请基于数据进行概括总结分析，凸显数据特征": (
        "战客中心37.45亿元，电信项目数领先但联通金额占67.0%，大单获取决定区域格局。"
    ),
    "浦东：2.75亿，个数移动41.3%，金额移动84.7%；请基于数据进行概括总结分析，凸显数据特征": (
        "浦东2.75亿元，移动项目数和金额均领先，数字经济核心区具备持续跟进价值。"
    ),
    "闵行：1.38亿，个数电信60.0%，金额电信53.6%；请基于数据进行概括总结分析，凸显数据特征": (
        "闵行1.38亿元，电信项目数60%、金额53.6%，在制造和城市服务场景保持领先。"
    ),
}


SOURCE_NOTES = [
    (
        "上海市服务业高质量发展解读",
        "https://www.shanghai.gov.cn/wzjd/20260601/6e8402b412bb4a2f8969fe0a64e08fd2.html",
    ),
    (
        "上海市服务业高质量发展措施",
        "https://fgw.sh.gov.cn/fgw_cyfz/20250317/bee76b58d9b74985b89dda953b7e5590.html",
    ),
    (
        "上海人工智能与城市数字化转型相关政策检索",
        "https://www.shanghai.gov.cn/",
    ),
]


def _paragraph_text(paragraph: ET.Element) -> str:
    return "".join(node.text or "" for node in paragraph.findall(".//a:t", OOXML_NS))


def _replace_paragraph(paragraph: ET.Element) -> int:
    text_nodes = paragraph.findall(".//a:t", OOXML_NS)
    if not text_nodes:
        return 0
    original = _paragraph_text(paragraph)
    if "{{" not in original:
        return 0

    missing: list[str] = []
    replacement_count = 0

    def replace_match(match: re.Match[str]) -> str:
        nonlocal replacement_count
        placeholder = match.group(1)
        if placeholder not in ANALYSIS_REPLACEMENTS:
            missing.append(placeholder)
            return match.group(0)
        replacement_count += 1
        return ANALYSIS_REPLACEMENTS[placeholder]

    updated = PLACEHOLDER_RE.sub(replace_match, original)
    if missing:
        raise PlaceholderFillError(
            "未配置占位符替换文案：" + "；".join(sorted(set(missing)))
        )
    if replacement_count == 0:
        return 0

    text_nodes[0].text = updated
    for node in text_nodes[1:]:
        node.text = ""
    return replacement_count


def _replace_slide_placeholders(xml_bytes: bytes) -> tuple[bytes, int]:
    root = ET.fromstring(xml_bytes)
    replacement_count = 0
    for paragraph in root.findall(".//a:p", OOXML_NS):
        replacement_count += _replace_paragraph(paragraph)
    return ET.tostring(root, encoding="utf-8", xml_declaration=True), replacement_count


def find_remaining_placeholders(pptx_path: Path) -> list[str]:
    remaining: list[str] = []
    with ZipFile(pptx_path) as package:
        for name in package.namelist():
            if not SLIDE_PART_RE.fullmatch(name):
                continue
            root = ET.fromstring(package.read(name))
            for paragraph in root.findall(".//a:p", OOXML_NS):
                remaining.extend(PLACEHOLDER_RE.findall(_paragraph_text(paragraph)))
    return remaining


def fill_analysis_placeholders(pptx_path: Path, output_path: Path) -> int:
    if not pptx_path.exists():
        raise PlaceholderFillError(f"输入 PPTX 不存在：{pptx_path}")
    output_path.parent.mkdir(parents=True, exist_ok=True)
    actual_output = output_path

    if pptx_path.resolve() == output_path.resolve():
        handle = tempfile.NamedTemporaryFile(delete=False, suffix=".pptx")
        handle.close()
        actual_output = Path(handle.name)

    replacement_count = 0
    try:
        with ZipFile(pptx_path, "r") as source, ZipFile(actual_output, "w") as target:
            for info in source.infolist():
                payload = source.read(info.filename)
                if SLIDE_PART_RE.fullmatch(info.filename):
                    payload, count = _replace_slide_placeholders(payload)
                    replacement_count += count
                target.writestr(info, payload)
        if actual_output != output_path:
            actual_output.replace(output_path)
    except Exception:
        if actual_output != output_path and actual_output.exists():
            actual_output.unlink()
        raise

    remaining = find_remaining_placeholders(output_path)
    if remaining:
        raise PlaceholderFillError(
            f"仍有 {len(remaining)} 个占位符未替换：" + "；".join(remaining[:5])
        )
    return replacement_count


def write_source_notes(output_path: Path) -> None:
    lines = [
        "# 上海市服务月报占位符填充来源说明",
        "",
        "本文件记录非接口占位符补写时参考的公开政策来源。招投标指标类文案来自 PPTX 已生成的表格、图表和占位符内指标，不再调用 FastAPI。",
        "",
    ]
    for title, url in SOURCE_NOTES:
        lines.append(f"- {title}: {url}")
    lines.append("")
    output_path.write_text("\n".join(lines), encoding="utf-8")


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="填充上海市服务月报中的分析性占位符。")
    parser.add_argument("--pptx", required=True, type=Path, help="输入 PPTX 文件路径。")
    parser.add_argument("--output", required=True, type=Path, help="输出 PPTX 文件路径。")
    parser.add_argument(
        "--sources-output",
        type=Path,
        help="可选：输出公开来源说明 Markdown。",
    )
    return parser.parse_args()


def main() -> None:
    args = parse_args()
    replacement_count = fill_analysis_placeholders(args.pptx, args.output)
    if args.sources_output:
        args.sources_output.parent.mkdir(parents=True, exist_ok=True)
        write_source_notes(args.sources_output)
    print(f"已替换 {replacement_count} 个分析占位符：{args.output}")


if __name__ == "__main__":
    main()
