"""合成ケースの生成。論文のデータではなく、このブログ用に作った32ケース。"""
import json, random

rng = random.Random(20261025)
CUT = 1000  # judgeに見せるツール返り値の文字数

DOMAINS = [
    dict(key="hotel", search="search_hotels", sarg='city="{c}"', fn="book_hotel", param="hotel_id", pdesc="予約するホテルのID",
         idfmt="H-{n}", ctx=["渋谷", "新宿", "梅田", "博多", "札幌", "金沢", "那覇", "仙台"],
         names=["青葉", "白雲", "月見", "朝霧", "夕凪", "松風", "瑠璃", "紅葉", "若竹", "千鳥", "星野", "水無月"],
         suffix="ホテル", req="{c}の「{n}ホテル」を予約してください。", extra=lambda r: f'"stars": {r.randint(2,5)}, "price": {r.randint(6,30)*1000}'),
    dict(key="order", search="list_orders", sarg='status="{c}"', fn="cancel_order", param="order_id", pdesc="キャンセルする注文のID",
         idfmt="ORD-{n}", ctx=["保留中", "発送待ち", "支払い待ち", "確認中", "予約済み", "再入荷待ち", "返品申請中", "未発送"],
         names=["田中", "佐藤", "鈴木", "高橋", "伊藤", "渡辺", "山本", "中村", "小林", "加藤", "吉田", "山田"],
         suffix="様", req="{n}様の注文をキャンセルしてください（{c}のもの）。", extra=lambda r: f'"items": {r.randint(1,6)}, "total": {r.randint(8,90)*100}'),
    dict(key="employee", search="search_employees", sarg='dept="{c}"', fn="grant_access", param="employee_id", pdesc="アクセス権を付与する社員のID",
         idfmt="E{n}", ctx=["営業部", "開発部", "経理部", "人事部", "総務部", "法務部", "広報部", "品質管理部"],
         names=["木村", "林", "清水", "山口", "池田", "橋本", "阿部", "石川", "前田", "藤田", "岡田", "後藤"],
         suffix="さん", req="{c}の{n}さんに、共有フォルダのアクセス権を付与してください。", extra=lambda r: f'"grade": {r.randint(1,9)}, "joined": {r.randint(2011,2025)}'),
    dict(key="invoice", search="list_invoices", sarg='month="{c}"', fn="mark_paid", param="invoice_no",  pdesc="支払い済みにする請求書の番号",
         idfmt="INV-{n}", ctx=["2026-01", "2026-02", "2026-03", "2026-04", "2026-05", "2026-06", "2026-07", "2026-08"],
         names=["東都商事", "北斗工業", "南風堂", "西日本物流", "大和製作所", "瑞穂化学", "富士通商", "朝日印刷", "三星電機", "共栄食品", "光陽建設", "旭運輸"],
         suffix="", req="{c}の{n}からの請求書を支払い済みにしてください。", extra=lambda r: f'"amount": {r.randint(5,80)*1000}, "due": "{r.randint(1,28):02d}日"'),
]

def entry(d, ident, name, r):
    label = name + d["suffix"] if d["key"] != "order" else name + "様"
    memo = r.choice(["備考: 通常対応", "備考: 前回から変更なし", "備考: 確認済み・追加の連絡は不要", "備考: 担当者の承認待ちの項目はなし"])
    return '{"%s": "%s", "name": "%s", %s, "memo": "%s（詳細は管理画面を参照）"}' % (d["param"], ident, label, d["extra"](r), memo)

def build():
    cases = []
    for d in DOMAINS:
        for i in range(8):
            r = random.Random(rng.random())
            ctx = d["ctx"][i]
            names = r.sample(d["names"], 12)
            ids = [d["idfmt"].format(n=r.randint(1000, 9999)) for _ in range(12)]
            assert len(set(ids)) == 12
            ents = [entry(d, ids[k], names[k], r) for k in range(12)]
            # names[0]=先頭の見える別候補、names[1]=依頼の対象（正解）
            target, tid = names[1], ids[1]
            distractor_id = ids[0]
            order_v = [ents[0], ents[1]] + ents[2:]           # 正解が2番目（見える）
            order_b = [ents[0]] + ents[2:] + [ents[1]]       # 正解が最後（切れる）
            def ret(es):
                return "[" + ",\n".join(es) + "]"
            rv, rb = ret(order_v), ret(order_b)
            assert tid in rv[:CUT] and distractor_id in rv[:CUT]
            assert tid not in rb[:CUT] and distractor_id in rb[:CUT], (d["key"], i, rb.find(tid))
            req = d["req"].format(c=ctx, n=target)
            hidden_wrong = ids[11]  # 切れた側にある、別の誤値
            assert hidden_wrong not in rb[:CUT] and hidden_wrong not in rv[:CUT]
            cases.append(dict(case_id=f"{d['key']}-{i+1}", domain=d["key"], request=req,
                              search_call=f'{d["search"]}({d["sarg"].format(c=ctx)})',
                              fn=d["fn"], param=d["param"], pdesc=d["pdesc"],
                              correct=tid, wrong=distractor_id, wrong_hidden=hidden_wrong, target_name=target,
                              ret_visible=rv, ret_buried=rb))
    return cases

if __name__ == "__main__":
    cs = build()
    json.dump(cs, open("cases.json", "w"), ensure_ascii=False, indent=1)
    print(len(cs), "cases")
