#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""给 三部门逐月_2026.json 的 salespersons 数组补「个人目标 / 达成率」。

数据源（逐人目标）—— 已探明，唯一权威：
  数据/kpi_scheme.json → people[]：
    · h2_months   = [7,8,9,10,11,12] 月个人目标（元）
    · annual_target = 个人年度目标（元）
    · dept / role / conf（分配依据：按人年度目标占比分摊部门 H2 余额）

产出（就地写回，幂等）：
  salespersons[i]['target']        当月个人目标（万元）—— 仅 7-12 月有源；1-6 月无逐人月目标 → null
  salespersons[i]['achieve']       当月达成率 = amt / target × 100（%）；无目标 → null
  salespersons[i]['target_annual'] 个人年度目标（万元）；无源 → null
  salespersons[i]['achieve_ytd']   个人 1-9 月累计实际 / 年度目标 × 100（%）；同一人各月行相同
  meta.salesperson_targets         口径说明 + 覆盖率
  meta.salesperson_target_gap      无逐人目标源 / 缺 1-6 月逐人月目标的如实记录

铁律：只加字段、不改任何金额；不编造目标 —— 找不到就是 null 并在 meta 里写明。

用法：env -u PYTHONPATH -u VIRTUAL_ENV /usr/bin/python3 脚本/apply_salesperson_targets.py
"""
import io
import json
import os
import shutil
import sys
from collections import defaultdict

HOME = os.path.expanduser("~")
W = f"{HOME}/Desktop/Hermes输出-工作类"
DATA = f"{W}/数据/三部门逐月_2026.json"
SCHEME = f"{W}/数据/kpi_scheme.json"

# 个人月目标仅覆盖 H2（7-12 月），对应 h2_months 下标 0..5
Q_MONTHS = ['2026-07', '2026-08', '2026-09', '2026-10', '2026-11', '2026-12']
WAN = 1e4


def load_scheme():
    """返回 {姓名: {'annual_wan': x, 'mon_wan': {月: 万元}}}。"""
    if not os.path.exists(SCHEME):
        return {}
    d = json.load(io.open(SCHEME, encoding="utf-8"))
    out = {}
    for p in (d.get("people") or []):
        nm = (p.get("name") or "").strip()
        if not nm:
            continue
        at = p.get("annual_target")
        hm = p.get("h2_months") or []
        mon = {}
        for i, m in enumerate(Q_MONTHS):
            if i < len(hm) and isinstance(hm[i], (int, float)):
                mon[m] = round(float(hm[i]) / WAN, 2)
        out[nm] = {
            "annual_wan": round(float(at) / WAN, 2) if isinstance(at, (int, float)) and at else None,
            "mon_wan": mon,
        }
    return out


def main():
    if not os.path.exists(DATA):
        print(f"❌ 找不到 {DATA}")
        return 1
    if not os.path.exists(SCHEME):
        print(f"❌ 找不到逐人目标源 {SCHEME}")
        return 1
    scheme = load_scheme()
    if not scheme:
        print(f"❌ {SCHEME} 无 people[]，无法取逐人目标")
        return 1

    J = json.load(io.open(DATA, encoding="utf-8"))
    sps = J.get("salespersons") or []

    # 个人 1-9 月累计实际（来自本数据源的 salespersons 行；口径与 customers/depts 一致）
    ytd = defaultdict(float)
    for r in sps:
        ytd[r.get("sp")] += r.get("amt") or 0.0

    n_hit_mon = n_hit_annual = 0
    no_source = set()          # 有 ERP 金额但完全无逐人目标
    no_month_h1 = defaultdict(set)   # 无 1-6 月逐人月目标的销售员
    for r in sps:
        sp = r.get("sp")
        s = scheme.get(sp)
        m = r.get("month")
        r["target"] = None
        r["achieve"] = None
        r["target_annual"] = None
        r["achieve_ytd"] = None
        if not s:
            no_source.add(sp)
            continue
        # 当月目标（7-12 月有源）
        tgt = s["mon_wan"].get(m)
        if tgt:
            r["target"] = tgt
            r["achieve"] = round((r.get("amt") or 0.0) / tgt * 100, 1) if tgt else None
            n_hit_mon += 1
        elif m and m < '2026-07':
            no_month_h1[sp].add(m)
        # 年度目标 + YTD 达成率
        if s["annual_wan"]:
            r["target_annual"] = s["annual_wan"]
            r["achieve_ytd"] = round(ytd.get(sp, 0.0) / s["annual_wan"] * 100, 1)
            n_hit_annual += 1

    meta = J.setdefault("meta", {})
    meta["salesperson_targets"] = {
        "source": "数据/kpi_scheme.json → people[]（h2_months=7-12月个人月目标；annual_target=个人年度目标）",
        "monthly_caliber": ("target = 当月个人目标（万元），仅 7-12 月有源（h2_months）；1-6 月无逐人月目标 → null。"
                            "achieve = 当月实际 / 当月目标 × 100（%）"),
        "annual_caliber": ("target_annual = 个人年度目标（万元）；"
                           "achieve_ytd = 个人 1-9 月累计实际 / 个人年度目标 × 100（%），同一人各月行相同"),
        "rows": len(sps), "rows_with_monthly_target": n_hit_mon, "rows_with_annual_target": n_hit_annual,
        "people_with_source": len(scheme), "people_no_source": sorted(no_source),
    }
    meta["salesperson_target_gap"] = {
        "monthly_1_6_missing": ("逐人目标源 kpi_scheme.json 只提供 H2（7-12 月）个人月目标，"
                                "1-6 月无逐人月目标 → 这些行 target/achieve 为 null（未编造）。"),
        "people_with_rows_but_no_target": sorted(no_source),
        "note": "未在 kpi_scheme.json people[] 中的销售员（多为新入职/离职/生命科学助理）无逐人目标，字段全部为 null。",
    }

    # ── 自检：只加字段，不动金额 ──
    s_amt = round(sum(r.get("amt") or 0 for r in sps), 2)
    print("================ 逐人目标门禁 ================")
    print(f"  逐人源: kpi_scheme.json people[]（{len(scheme)} 人）")
    print(f"  salespersons 行数={len(sps)}  当月目标命中={n_hit_mon}  年度目标命中={n_hit_annual}")
    print(f"  无逐人目标源的销售员 {len(no_source)} 人: {sorted(no_source)[:20]}")
    print(f"  Σamt（应不变）= {s_amt:,.2f} 万")

    shutil.copy2(DATA, DATA + ".bak-pre-sptarget")
    io.open(DATA, "w", encoding="utf-8").write(
        json.dumps(J, ensure_ascii=False, separators=(",", ":")))
    print(f"\n✅ 已写回 {DATA}（备份 .bak-pre-sptarget）")
    return 0


if __name__ == "__main__":
    sys.exit(main())
