"""v2.7 の試算ページのデータ（const D）の③⑦（fam_p1・fam_p5）だけを、ドリンクバーを直した店の形で回し直した結果に入れ替える（2026-10-24）。
使い方: python3 merge_v27.py <枝の v2.7 のページ> <③⑦の結果 rows_v27_p1p5.json> <公開中のページ> <出力するページ> <比べた結果.txt>
- ほかの店の行は枝の v2.7 のまま（同じモデル・同じ店の形なので回し直さない）
- 公開中のページの const D の1行・見出しの版・前提の「配膳の分担」だけを入れ替える（費用の欄・LP 用の色は残す）"""
import json, os, re, sys
import haizen_sim as h
br, newp, live, out, cmp_out = sys.argv[1:6]
STO = ("fam_p1", "fam_p5")
getD = lambda s: [l for l in s.split("\n") if l.startswith("const D = ")]
bl = getD(open(br, encoding="utf-8").read()); assert len(bl) == 1
D = json.loads(bl[0][len("const D = "):].rstrip(";"))
N = json.load(open(newp, encoding="utf-8"))
assert N["common"] == D["common"], "モデルの値が枝の v2.7 と違う"
keys = D["k"][:-1]
newrows = []
for r in N["rows"]:
    row = [round(r[k], 3) if i >= 7 else r[k] for i, k in enumerate(keys)]
    row.append(1 if r["staff_wait_mean"] >= h.NG_MIN else 0)
    newrows.append(row)
it = iter(newrows); old = {}
for i, r in enumerate(D["r"]):
    if r[0] in STO:
        n = next(it)
        assert n[:7] == r[:7], ("条件の並びが違う", n[:7], r[:7])
        old[tuple(r[:7])] = r
        D["r"][i] = n
assert next(it, None) is None
# 店の情報と平面図（build_page_v26.py と同じ作り方）
q = lambda a: [round(v, 2) for v in a]
for k in STO:
    s = dict(N["stores"][k]); dl = s.pop("dist_list")
    an = json.load(open(os.path.join(h.LAYOUT_DIR, s["layout"] + ("_efficient_corner" if k == "fam_p1" else "_crammed") + "_analysis.json"), encoding="utf-8"))
    assert dl == [t["dist"] for t in an["tables"]], "試算に使った距離が店の形と違う"
    s["short"] = s["label"]; s["label"] = f"標準ファミレス（{s['short']}）"; s["dist_mean"] = round(sum(dl) / len(dl), 1)
    s = {a: s[a] for a in D["stores"][k]}   # 枝のページと同じ項目だけ
    D["stores"][k] = s
    L = json.load(open(os.path.join(h.LAYOUT_DIR, s["layout"] + ("_efficient_corner" if k == "fam_p1" else "_crammed") + ".json"), encoding="utf-8"))["layout"]
    W, Dd = L["outer"]["w"], L["outer"]["d"]
    D["plans"][k] = {"w": W, "d": Dd, "outline": L.get("outline") or [[0, 0], [W, 0], [W, Dd], [0, Dd]],
                     "rooms": [q(r["rect"]) + [r["kind"], r["label"]] for r in L["rooms"] if r["kind"] != "outside"],
                     "walls": [q(w["rect"]) for w in L["walls"]],
                     "tables": [q([t["x"], t["y"], t["x"] + t["w"], t["y"] + t["h"]]) + [t["seats"]] for t in L["tables"]],
                     "dish": [q(d["rect"]) for d in L["dish_up"]], "standby": q(L["robot_standby"]["rect"]),
                     "ent": [L["entrance"]["side"], L["entrance"]["a0"], L["entrance"]["a1"]]}
gens = {g["generation"] for g in json.load(open(os.path.join(h.LAYOUT_DIR, "summary.json"), encoding="utf-8"))}
for f in os.listdir(h.LAYOUT_DIR):
    if f.endswith(".json") and f != "summary.json":
        gens.add(json.load(open(os.path.join(h.LAYOUT_DIR, f), encoding="utf-8"))["meta"]["generation"])
assert len(gens) == 1, gens
D["layout_generation"] = gens.pop()
# 比べる
lines = [f"v2.7（枝・店の形 82023936eb99）と、③⑦をドリンクバーを直した店の形（{D['layout_generation']}）で回し直したものの比較"]
ki = {k: i for i, k in enumerate(D["k"])}
for k in STO:
    rs = [r for r in D["r"] if r[0] == k]
    for m in ("entry_wait_mean", "staff_wait_mean", "dish_wait_mean", "robot_share"):
        d = [r[ki[m]] - old[tuple(r[:7])][ki[m]] for r in rs]
        lines.append(f"{k} {m}: 差の平均 {sum(d)/len(d):+.3f}  最小 {min(d):+.3f}  最大 {max(d):+.3f}")
    lines.append(f"{k} 店が回らない {sum(old[tuple(r[:7])][-1] for r in rs)} -> {sum(r[-1] for r in rs)}  卓までの平均 {D['stores'][k]['dist_mean']}")
lines.append(f"全体の店が回らない {sum(r[-1] for r in D['r'])} / {len(D['r'])} 条件")
open(cmp_out, "w", encoding="utf-8").write("\n".join(lines) + "\n"); print("\n".join(lines))
# 公開中のページに入れる
s = open(live, encoding="utf-8").read()
ol = getD(s); assert len(ol) == 1
s = s.replace(ol[0], "const D = " + json.dumps(D, ensure_ascii=False, separators=(",", ":")) + ";")
assert len(re.findall(r"試作 v2\.\d+", s)) == 1
s = re.sub(r"試作 v2\.\d+", "試作 v2.7", s)
o = '["配膳の分担", "ロボットとスタッフのうち先に空いた方が運ぶ"],'
assert s.count(o) == 1
s = s.replace(o, '["配膳の分担", `ロボットが配膳するときは、料理はまずロボットを待つ。${Math.round(c.robot_first_wait_s / 60)}分たってもロボットが空かなければ、そこからはロボットとスタッフのうち先に空いた方が運ぶ。割れ物を人だけが運ぶ設定と、ロボットなしはスタッフが運ぶ（v2.7 から。それまでは、はじめから先に空いた方が運んでいた）`],')
open(out, "w", encoding="utf-8").write(s)
print(len(s), "bytes")
