#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
模块房光储 · 中美澳利润测算器
用法: python3 测算器.py            # 输出全部报表
      python3 测算器.py --fx 7.0   # 改汇率
所有参数集中在下方 CONFIG 区，供应商正式报价到位后回填即可复算。
"""
import argparse, json

# ============ 汇率 ============
FX = {"USD_CNY": 7.15, "AUD_CNY": 4.70}

# ============ 采购价（¥/件，供应商正式报价到位后回填） ============
BUY = {
 "bat10":    {"name":"磷酸铁锂储能电池 10kWh 壁挂(含BMS)","cny":6800,"kg":95, "cbm":0.13, "cat":"battery"},
 "bat5":     {"name":"磷酸铁锂储能电池 5kWh 壁挂(含BMS)", "cny":3700,"kg":52, "cbm":0.08, "cat":"battery"},
 "inv_hyb5": {"name":"混合储能逆变器 5kW/48V",           "cny":2900,"kg":12, "cbm":0.03, "cat":"inverter"},
 "inv_hyb8": {"name":"混合储能逆变器 8kW/48V",           "cny":4200,"kg":20, "cbm":0.05, "cat":"inverter"},
 "pv550":    {"name":"单晶光伏组件 550W",                "cny": 420,"kg":27, "cbm":0.075,"cat":"pv"},
 "bracket6": {"name":"光伏支架套件(6kW)",                "cny": 900,"kg":60, "cbm":0.12, "cat":"bracket"},
 "cable":    {"name":"光伏电缆+MC4+直流箱+配电套件",       "cny": 700,"kg":18, "cbm":0.04, "cat":"cable"},
 "meter":    {"name":"双向电表/CT+网关+防孤岛套件",        "cny": 600,"kg": 3, "cbm":0.01, "cat":"meter"},
 "ems":      {"name":"EMS/铭牌/合规文件套件",             "cny": 200,"kg": 1, "cbm":0.005,"cat":"ems"},
}

# ============ 美国关税（2026-09 最乐观叠加口径，以 CBP 裁定为准） ============
US_DUTY = {
 "battery": 0.824,   # MFN3.4% + 301 25% + 对等 54%
 "inverter":0.550,   # 301 25% + 对等 30%
 "pv":      0.950,   # 301 50% + 对等 30% + 232 15%（12/4起）
 "bracket": 0.800,   # 232钢25% + 301 25% + 对等 30%
 "cable":   0.550, "meter":0.550, "ems":0.550,
}
AU_DUTY = 0.0        # ChAFTA 凭原产地证 0 关税

# ============ 海运（2026-08 市场） ============
FREIGHT = {"US": 7500, "AU": 3000}   # 40HQ 整柜 USD
CBM_40HQ, KG_40HQ = 68.0, 22000      # 40HQ 容积/限重
INSURANCE = 0.005
PACK = {"kg":1.08, "cbm":1.15}       # 外箱包装系数

# ============ 配置 ============
CONF = {
 "A 10kWh+6.6kW": [("bat10",1),("inv_hyb5",1),("pv550",12),("bracket6",1),("cable",1),("meter",1),("ems",1)],
 "B 20kWh+10kW":  [("bat10",2),("inv_hyb8",1),("pv550",18),("bracket6",2),("cable",1),("meter",1),("ems",1)],
}
POST = {  # 目的国后端附加成本
 "US": {"brokerage":250, "cert_amort_kit":900, "cert_amort_prefab":650, "prefab_labor":450},
 "AU": {"brokerage":350, "cert_amort_kit":320, "cert_amort_prefab":240, "prefab_labor":380},
}
RETAIL = {  # 渠道零售/报价（市场区间中值）
 "US": {"A 10kWh+6.6kW":[6500,9500,14000], "B 20kWh+10kW":[9000,14000,22000]},
 "AU": {"A 10kWh+6.6kW":[8000,15500,23000],"B 20kWh+10kW":[8000,15500,23000]},
}


def bill(cfg_items, market):
    """返回一套系统的成本结构（目的国货币）"""
    fx = FX["USD_CNY"] if market=="US" else FX["AUD_CNY"]
    fob_cny = sum(BUY[k]["cny"]*q for k,q in cfg_items)
    kg  = sum(BUY[k]["kg"]*q  for k,q in cfg_items) * PACK["kg"]
    cbm = sum(BUY[k]["cbm"]*q for k,q in cfg_items) * PACK["cbm"]
    fr  = FREIGHT[market]
    ship = max(cbm*fr/CBM_40HQ, kg*fr/KG_40HQ)     # 拼柜按体积/重量取严分摊
    fob = fob_cny/fx
    ins = fob*INSURANCE
    cif = fob + ship + ins
    if market=="US":
        duty = sum((BUY[k]["cny"]*q/fx)*US_DUTY[BUY[k]["cat"]] for k,q in cfg_items)
    else:
        duty = cif*AU_DUTY
    return dict(fob_cny=fob_cny, fob=fob, ship=ship, ins=ins, cif=cif, duty=duty,
                landed=cif+duty, kg=kg, cbm=cbm, sets_per_40hq=int(min(CBM_40HQ/cbm, KG_40HQ/kg)))


def landed_total(b, market, mode):
    p = POST[market]
    extra = p["cert_amort_kit"] if mode=="kit" else p["cert_amort_prefab"] + p["prefab_labor"]
    return b["landed"] + p["brokerage"] + extra


def report(market):
    cur = "$" if market=="US" else "A$"
    print("="*94)
    print(f"【{'🇺🇸 美国' if market=='US' else '🇦🇺 澳洲'}】成本与毛利   1USD={FX['USD_CNY']}CNY  1AUD={FX['AUD_CNY']}CNY"
          f"   运费40HQ {cur}{FREIGHT[market]:,}")
    print("="*94)
    for name, items in CONF.items():
        b = bill(items, market)
        print(f"\n▌{name}   出厂价 ¥{b['fob_cny']:,} = {cur}{b['fob']:,.0f}   毛重 {b['kg']:.0f}kg  "
              f"体积 {b['cbm']:.2f}m³   单40HQ可装 {b['sets_per_40hq']} 套")
        print(f"   运费 {cur}{b['ship']:,.0f} | 保险 {cur}{b['ins']:,.0f} | CIF {cur}{b['cif']:,.0f} | "
              f"关税 {cur}{b['duty']:,.0f} | 到{market}清关前 {cur}{b['landed']:,.0f}")
        for mode, label in [("kit","裸机套件自行安装"),("prefab","模块房出厂预装")]:
            base = landed_total(b, market, mode)
            print(f"   ├─ {label}: 落地总成本 {cur}{base:,.0f}")
            for tier, retail in zip(["A 廉价/DIY","B 中端","C 品牌"], RETAIL[market][name]):
                gp = retail-base
                bar = "█"*int(max(0,gp/retail)*30)
                print(f"   │    {tier:10s} 零售 {cur}{retail:>7,}  毛利 {cur}{gp:>7,.0f}  "
                      f"{gp/retail*100:>3.0f}%  {bar}")
    print()


def sensitivity():
    global US_DUTY
    print("="*94); print("【敏感性分析】基准: 配置A(10kWh+6.6kW) 美国 中端零售 $9,500"); print("="*94)
    items = CONF["A 10kWh+6.6kW"]
    print("\n① 关税情景（决定美国利润的第一变量）")
    scen = [
        ("当前全额叠加", US_DUTY),
        ("取消对等关税(-30pp)", {k:max(0,v-0.30) for k,v in US_DUTY.items()}),
        ("回到2024年301口径", {"battery":0.11,"inverter":0.25,"pv":0.25,"bracket":0.25,"cable":0.25,"meter":0.25,"ems":0.25}),
        ("第三国转口(0关税)", {k:0.0 for k in US_DUTY}),
    ]
    saved = dict(US_DUTY)
    for nm, rm in scen:
        US_DUTY = rm
        b = bill(items,"US"); base = landed_total(b,"US","kit")
        print(f"   {nm:24s} 落地 ${base:>6,.0f}  毛利 ${9500-base:>6,.0f}  ({(9500-base)/9500*100:>3.0f}%)")
    US_DUTY = saved

    print("\n② 中国出厂价变动（澳洲 vs 美国，中端渠道）")
    for d in [-0.10,0,0.10,0.20,0.30]:
        tmp = {k:dict(v) for k,v in BUY.items()}
        for k in BUY: BUY[k]["cny"] = tmp[k]["cny"]*(1+d)
        bu = bill(items,"US"); ba = bill(items,"AU")
        lu, la = landed_total(bu,"US","kit"), landed_total(ba,"AU","kit")
        print(f"   出厂价 {d*100:+4.0f}%   美国 落地${lu:>6,.0f} 毛利${9500-lu:>6,.0f}({(9500-lu)/9500*100:>3.0f}%)"
              f"   |   澳洲 落地A${la:>6,.0f} 毛利A${15500-la:>7,.0f}({(15500-la)/15500*100:>3.0f}%)")
        for k in BUY: BUY[k]["cny"] = tmp[k]["cny"]

    print("\n③ 汇率敏感度（配置A，中端零售固定）")
    base_fx = FX["USD_CNY"]
    for fx in [6.8,7.0,7.15,7.4,7.6]:
        FX["USD_CNY"] = fx
        b = bill(items,"US"); base = landed_total(b,"US","kit")
        print(f"   1USD={fx:.2f}  落地 ${base:>6,.0f}  毛利 ${9500-base:>6,.0f}  ({(9500-base)/9500*100:>3.0f}%)")
    FX["USD_CNY"] = base_fx
    print()


def cost_structure():
    print("="*94); print("【成本结构拆解】配置A · 美国 · 中端零售 $9,500"); print("="*94)
    b = bill(CONF["A 10kWh+6.6kW"],"US"); base = landed_total(b,"US","kit")
    rows = [("中国出厂价", b["fob"]), ("海运+保险", b["ship"]+b["ins"]),
            ("美国进口关税", b["duty"]), ("清关+认证摊销+后端", base-b["landed"]),
            ("渠道毛利", 9500-base)]
    for n,v in rows:
        print(f"   {n:20s} ${v:>7,.0f}   {v/9500*100:>4.0f}% 零售   {'█'*int(v/9500*40)}")
    print(f"\n   关税/出厂货值 = {b['duty']/b['fob']*100:.0f}%      关税/落地成本 = {b['duty']/base*100:.0f}%")
    print(f"   预装 vs 裸机 落地成本差 = ${landed_total(b,'US','prefab')-base:,.0f}\n")


if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("--fx", type=float, default=None, help="USD/CNY 汇率")
    a = ap.parse_args()
    if a.fx: FX["USD_CNY"] = a.fx
    report("AU"); report("US"); sensitivity(); cost_structure()
    json.dump({"FX":FX,"BUY":BUY,"US_DUTY":US_DUTY,"FREIGHT":FREIGHT},
              open("/tmp/kws_params.json","w"), ensure_ascii=False, indent=1)
