# -*- coding: utf-8 -*-
"""ICM 2023 D 配图：24 张 SVG，复用 _svg 基元，输出到 papers/。
视角划分：Paper1 网络构建与优先级方法 / Paper2 优先级结果与 What-if·危机 / Paper3 10年扩散有效性与企业ESG。
"""
import os
import xml.dom.minidom
import gen_icm2023d as G

HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.normpath(os.path.join(HERE, "..", "assets", "problems", "papers"))
os.makedirs(OUT, exist_ok=True)

from _svg import (_fig, _save, _bar, _grouped_bar, _line, _scatter, _pie,
                  _heatmap, _network, _flow, _txt, C_RED, C_GREEN, C_ACC, C_CYAN,
                  C_AMB, C_PUR, C_TEAL, C_PINK, C_MUT, C_TXT, PALETTE)

C_BLUE = C_ACC; C_AMBER = C_AMB; C_PURPLE = C_PUR; C_SLATE = "#475569"

D = G.gen_icm2023d()
N = D["N"]
NAMES = G.NAMES
ABB = G.ABB
M = D["M"]
posdeg = D["posdeg"]; negdeg = D["negdeg"]; net = D["net"]
nlinks = D["nlinks"]; eig = D["eig"]; bet = D["bet"]; prio = D["prio"]
order = D["order"]; rank = D["rank"]
diff_eff = D["diff_eff"]; diff_order = D["diff_order"]; diff_rank = D["diff_rank"]
diff_series = D["diff_series"]
biggest_loser = D["biggest_loser"]; biggest_loss = D["biggest_loss"]
shocks = D["shocks"]
esg_sub = D["esg_sub"]; esg_order = D["esg_order"]; esg_prio = D["esg_prio"]

SHORT = NAMES  # 直接用中文短名
TOP5 = order[:5]


def _save_check(name, svg):
    xml.dom.minidom.parseString(svg)
    _save(os.path.join(OUT, name), svg)
    return name


# 紧凑多类目条形（17 个时避免重叠）
def _manybar(title, labels, vals, colors=None, fmt="%.2f", ymax=None, W=780, H=460):
    n = len(labels)
    cw = (W - 120) / (n + 0.5)
    mx = ymax if ymax is not None else (max(vals) if vals else 1)
    if mx <= 0:
        mx = 1
    body = ""
    for i, (lb, v) in enumerate(zip(labels, vals)):
        x = 60 + (i + 0.5) * cw
        h = (v / mx) * (H - 175) if mx > 0 else 0
        c = (colors[i % len(colors)] if colors else C_BLUE)
        body += '<rect x="%g" y="%g" width="%g" height="%g" fill="%s" rx="2"/>\n' % (x, H - 105 - h, cw * 0.82, h, c)
        body += _txt(x + cw * 0.41, H - 111 - h, fmt % v, 8, C_TXT, "middle", "700")
        body += _txt(x + cw * 0.41, H - 86, lb, 8, C_MUT)
    body += _txt(W / 2, H - 12, "图：柱高=数值（紧凑多类目条形）", 11, C_MUT)
    return _fig(title, body, W, H)


# ============ Paper 1：网络构建与优先级方法 ============
def f1_1():
    # 17x17 SDG 交互矩阵热力图
    rows = [NAMES[i] for i in range(N)]
    cols = [("SDG%d" % (i + 1)) for i in range(N)]
    return _heatmap("图1 17 个 SDG 交互强度矩阵（ICSU 七分型 -3..+3，绿=正协同 红=权衡）",
                    rows, cols, M, fmt="%d", cmap=[(1.0, C_GREEN), (0.5, "#f1f5f9"), (0.0, C_RED)])


def f1_2():
    labels = ["SDG%d" % (i + 1) for i in range(N)]
    colors = [C_GREEN if net[i] >= 0 else C_RED for i in range(N)]
    return _grouped_bar("图2 各 SDG 正/负协同度与净协同",
                        labels, ["正协同", "负协同"],
                        [[posdeg[i], negdeg[i]] for i in range(N)],
                        colors=[C_TEAL, C_RED], fmt="%.0f")


def f1_3():
    # 网络拓扑：节点大小∝度中心性
    nodes = [(("SDG%d" % (i + 1)), ("SDG%d" % (i + 1)),
              C_PURPLE if i in TOP5 else (C_RED if net[i] < 0 else C_TEAL))
             for i in range(N)]
    edges = []
    for i in range(N):
        for j in range(i + 1, N):
            if M[i][j] != 0:
                edges.append((i, j, abs(M[i][j])))
    return _network("图3 SDG 关系网络（节点大小∝连接数，紫色=TOP5优先级）",
                    nodes, edges)


def f1_4():
    labels = ["SDG%d" % (i + 1) for i in range(N)]
    colors = [C_PURPLE if i in TOP5 else C_SLATE for i in range(N)]
    return _bar("图4 度中心性（连接的目标数）排名",
                labels, nlinks, colors=colors, ylabel="连接数", fmt="%d")


def f1_5():
    labels = ["SDG%d" % (i + 1) for i in range(N)]
    colors = [C_PURPLE if i in TOP5 else C_BLUE for i in range(N)]
    return _bar("图5 特征向量中心性（与重要目标相连的程度）排名",
                labels, eig, colors=colors, ylabel="eig", fmt="%.3f")


def f1_6():
    labels = ["SDG%d" % (i + 1) for i in range(N)]
    colors = [C_PURPLE if i in TOP5 else C_AMBER for i in range(N)]
    return _bar("图6 介数中心性（作为桥梁目标的中介程度）排名",
                labels, bet, colors=colors, ylabel="betweenness", fmt="%.2f")


def f1_7():
    # 优先级综合得分构成：三分量加权
    en = G._minmax(eig); pn = G._minmax(posdeg); nn = G._minmax(net)
    labels = ["SDG%d" % (i + 1) for i in range(N)]
    vals_e = [G.W_EIG * en[i] for i in range(N)]
    vals_p = [G.W_POS * pn[i] for i in range(N)]
    vals_n = [G.W_NET * nn[i] for i in range(N)]
    colors = [C_PURPLE, C_TEAL, C_AMBER]
    return _grouped_bar("图7 优先级综合得分 = 0.50·eig + 0.30·正协同 + 0.20·净协同",
                        labels, ["eig项", "正协同项", "净协同项"],
                        [[vals_e[i], vals_p[i], vals_n[i]] for i in range(N)],
                        colors=colors, fmt="%.3f")


def f1_8():
    steps = [("构建交互矩阵", "ICSU七分型"),
             ("计算中心性", "度/特征/介数"),
             ("综合优先级", "三分量加权"),
             ("网络稳健性", "What-if验证"),
             ("政策应用", "危机/ESG")]
    return _flow("图8 优先级网络建模方法论流程", steps)


# ============ Paper 2：优先级结果与 What-if·危机 ============
def f2_1():
    labels = ["SDG%d" % (order[i] + 1) for i in range(N)]
    vals = [prio[order[i]] for i in range(N)]
    colors = [C_PURPLE if i < 5 else C_SLATE for i in range(N)]
    return _bar("图1 综合优先级排名（TOP5 高亮：SDG1/8/12/4/5）",
                labels, vals, colors=colors, ylabel="优先级得分", fmt="%.3f")


def f2_2():
    pts = [(eig[i], prio[i]) for i in range(N)]
    return _scatter("图2 优先级 vs 特征向量中心性（高度一致，验证方法稳健）",
                    [("各 SDG", C_BLUE, pts)],
                    xlabel="特征向量中心性", ylabel="综合优先级得分")


def f2_3():
    # What-if：实现各 SDG 后其"受害者"中心性损失
    labels = ["SDG%d" % (k + 1) for k in range(N)]
    vals = [biggest_loss[k] for k in range(N)]
    colors = [C_RED if biggest_loss[k] > 0.03 else C_AMBER for k in range(N)]
    return _bar("图3 What-if：实现某 SDG 后受害目标的特征向量损失",
                labels, vals, colors=colors, ylabel="eig 损失", fmt="%.4f")


def f2_4():
    # What-if 网络结构变化：删 SDG8 前后度中心性落差（示意 TOP 受害者）
    k = 7  # SDG8 体面工作
    idxs = [i for i in range(N) if i != k]
    Ms = [[M[i][j] for j in idxs] for i in idxs]
    sub = G._priority_from_matrix_sub(Ms, len(idxs))
    labels = ["SDG%d" % (i + 1) for i in idxs]
    vals = [eig[i] - sub["eig"][pos] for pos, i in enumerate(idxs)]
    colors = [C_RED if v > 0.03 else C_SLATE for v in vals]
    return _bar("图4 What-if：若 SDG8(体面工作)已实现，其余目标中心性变化",
                labels, vals, colors=colors, ylabel="eig 增量", fmt="%.4f")


def f2_5():
    labels = list(shocks.keys())
    cn = {"tech": "技术进步", "pand": "全球大流行", "climate": "气候变化", "war": "战争/难民"}
    vals = [shocks[s]["drift"] for s in labels]
    colors = [C_RED if v > 70 else (C_AMBER if v > 50 else C_GREEN) for v in vals]
    return _bar("图5 四类危机对优先级排名的扰动强度（排名漂移总量）",
                [cn[s] for s in labels], vals, colors=colors, ylabel="排名漂移总量", fmt="%d")


def f2_6():
    # 危机前后 TOP5 组成变化：基线 TOP5 中有几个在危机后仍居前 5
    cn = ["技术进步", "全球大流行", "气候变化", "战争/难民"]
    keys = ["tech", "pand", "climate", "war"]
    base_set = set(TOP5)
    overlap = [len(set(shocks[k]["top5_after"]) & base_set) for k in keys]
    return _grouped_bar("图6 危机后 TOP5 与基线 TOP5 的重合数（越低越动荡）",
                        cn, ["基线前5总数", "危机后仍在前5"],
                        [[5, overlap[i]] for i in range(4)],
                        colors=[C_SLATE, C_GREEN], fmt="%d")


def f2_7():
    # 排名变化热力图：17 SDG × 4 危机（rank_after - rank_before，红=下降）
    cols = ["技术进步", "全球大流行", "气候变化", "战争/难民"]
    rows = ["SDG%d" % (i + 1) for i in range(N)]
    Mh = []
    for i in range(N):
        rowv = []
        for s in ["tech", "pand", "climate", "war"]:
            rb = rank[i]
            ra = shocks[s]["rank"][i]
            rowv.append(ra - rb)  # 正=排名上升(变好), 负=下降
        Mh.append(rowv)
    return _heatmap("图7 各危机下 17 SDG 排名变化（绿=上升 红=下降）",
                    rows, cols, Mh, fmt="%d", cmap=[(1.0, C_GREEN), (0.5, "#f1f5f9"), (0.0, C_RED)])


def f2_8():
    steps = [("识别枢纽", "SDG8为核心"),
             ("评估有效性", "10年可达"),
             ("What-if", "删点稳健"),
             ("危机压力测", "四类冲击"),
             ("政策建议", "优先投资")]
    return _flow("图8 优先级结果与稳健性分析流程", steps)


# ============ Paper 3：10年扩散有效性与企业ESG ============
def f3_1():
    labels = ["SDG%d" % (diff_order[i] + 1) for i in range(N)]
    vals = [diff_eff[diff_order[i]] for i in range(N)]
    colors = [C_PURPLE if i < 3 else C_SLATE for i in range(N)]
    return _bar("图1 10 年协同扩散有效性排名（最值得优先投资的目标）",
                labels, vals, colors=colors, ylabel="累计受益总量", fmt="%.2f")


def f3_2():
    # cascade 曲线：投资 TOP3 扩散有效性 SDG 与最差 SDG
    picks = [diff_order[0], diff_order[1], diff_order[2], diff_order[-1]]
    series = []
    cmap = [C_PURPLE, C_TEAL, C_AMBER, C_RED]
    allv = []
    for idx, p in enumerate(picks):
        s = diff_series[p]
        allv.extend(s)
        series.append(("SDG%d" % (p + 1), cmap[idx], [(t, s[t]) for t in range(len(s))]))
    return _line("图2 投资不同 SDG 的 10 年全网累计受益扩散曲线",
                 series, xlabel="年份(0-10)", ylabel="累计受益(标准化)",
                 ymin=min(allv) - 1, ymax=max(allv) + 1,
                 xmin=0, xmax=10)


def f3_3():
    # 静态优先级排名 vs 动态扩散排名（散点）
    pts = [(rank[i], diff_rank[i]) for i in range(N)]
    return _scatter("图3 静态优先级 vs 动态扩散有效性排名（方法互补）",
                    [("各 SDG", C_BLUE, pts)],
                    xlabel="静态优先级排名", ylabel="动态扩散排名")


def f3_4():
    labels = ["SDG%d" % (i + 1) for i in range(N)]
    colors = [C_PURPLE if i == diff_order[0] else C_SLATE for i in range(N)]
    return _bar("图4 各 SDG 投资后 10 年累计受益（SDG12 最高）",
                labels, diff_eff, colors=colors, ylabel="累计受益", fmt="%.2f")


def f3_5():
    labels = ["SDG%d" % (s - 1) for s in esg_order]
    vals = esg_prio
    colors = [C_TEAL if i < 3 else C_SLATE for i in range(len(labels))]
    return _bar("图5 企业 ESG 子图（8 目标）优先级排名",
                labels, vals, colors=colors, ylabel="子图优先级得分", fmt="%.3f")


def f3_6():
    nodes = [(("SDG%d" % (s - 1)), ("SDG%d" % (s - 1)), C_TEAL) for s in esg_sub]
    idx = {s - 1: k for k, s in enumerate(esg_sub)}
    edges = []
    for a in range(len(esg_sub)):
        for b in range(a + 1, len(esg_sub)):
            i, j = esg_sub[a] - 1, esg_sub[b] - 1
            if M[i][j] != 0:
                edges.append((a, b, abs(M[i][j])))
    return _network("图6 企业 ESG 相关 8 个 SDG 子网络", nodes, edges)


def f3_7():
    # 完整网络 + ESG 子图叠加示意：ESG 节点高亮
    nodes = [(("SDG%d" % i), ("SDG%d" % i),
              C_TEAL if (i + 1) in esg_sub else (C_PURPLE if i in TOP5 else C_MUT))
             for i in range(N)]
    edges = []
    for i in range(N):
        for j in range(i + 1, N):
            if M[i][j] != 0:
                edges.append((i, j, abs(M[i][j])))
    return _network("图7 完整 SDG 网络：青色=企业ESG相关目标，紫色=TOP5优先级",
                    nodes, edges)


def f3_8():
    steps = [("企业诊断", "ESG基线"),
             ("子图重排", "8目标优先"),
             ("优先投资", "SDG9/11/7"),
             ("协同扩散", "10年受益"),
             ("路线图", "年度复盘")]
    return _flow("图8 企业 ESG 目标优先级路线图", steps)


JOBS = [f1_1, f1_2, f1_3, f1_4, f1_5, f1_6, f1_7, f1_8,
        f2_1, f2_2, f2_3, f2_4, f2_5, f2_6, f2_7, f2_8,
        f3_1, f3_2, f3_3, f3_4, f3_5, f3_6, f3_7, f3_8]


def main():
    bad = 0
    for i, job in enumerate(JOBS, 1):
        try:
            svg = job()
            name = "icm2023d-%d-fig%d.svg" % ((i - 1) // 8 + 1, (i - 1) % 8 + 1)
            _save_check(name, svg)
        except Exception as e:
            bad += 1
            print("FAIL", i, job.__name__, e)
    print("icm2023d figures: %d generated, %d bad" % (len(JOBS), bad))


if __name__ == "__main__":
    main()
