import asyncio, json, re, sys
from pathlib import Path
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, AssistantMessage, ResultMessage

ROOT = Path("/tmp/exp-slide"); OUT = ROOT / "runs2"
KEY = """【元データ（百万円、monthly.csv）】
4月 East15 West12 Other9／5月 16,13,10／6月 19,15,11／7月 21,14,11／8月 23,15,12／9月 26,16,12。Q1=4〜6月、Q2=7〜9月。
【正しい値】月別合計: 4月36、5月39、6月45、7月46、8月50、9月54。Q1合計120、Q2合計150。
前月比: 5月+8.3%（8.33）、6月+15.4%（15.38）、7月+2.2%（2.22）、8月+8.7%（8.70）、9月+8.0%（8.00）。4月は前月が無く算出不可。
Q2地域別売上と構成比: East70（46.7%）、West45（30.0%）、Other35（23.3%）。
Q1地域別: East50、West40、Other30。増加額と増加率: East+20（+40.0%）、West+5（+12.5%）、Other+5（+16.7%）、全体+30（+25.0%）。
Q1構成比: East41.7%、West33.3%、Other25.0%。
小数の丸めは整数や小数第1位の四捨五入なら正しいとみなす（例: 8.3%を8%や8.33%と書くのは可）。
【ラベル】WRONG=数字・計算・対応づけ（どの月・地域の値か）が誤っている行／ok=正しい数字を含む行／NA=数字の主張を含まない行（見出し・装飾・CSSなど）。
元データから導けない数字を新たに書いた行（例: 存在しない月の値、資料に無い予測）もWRONG。1行に誤りが複数あっても WRONG 1つでよい。"""

def numbered(path):
    lines = []
    for n, l in enumerate(Path(path).read_text().splitlines(), 1):
        s = l.strip()
        if not s or s == "---" or s.startswith("marp:") or s.startswith("theme:") or s.startswith("paginate:") or s.startswith("class:") or s.startswith("<!--") and s.endswith("-->") and len(s) < 12:
            continue
        lines.append((n, s))
    return lines

async def judge_one(deck, sem):
    async with sem:
        lines = numbered(deck)
        body = "\n".join(f"{n}\t{s}" for n, s in lines)
        prompt = (KEY + "\n\n【採点対象】Marpスライドの行（行番号<TAB>本文）。1行ずつ、ラベルを付けてください。"
                  "文脈（前後の行や見出し）も踏まえて判断します。\n"
                  "出力はJSONの配列のみ。各要素は {\"line\":行番号, \"labels\":[...], \"why\":\"誤りの場合だけ短い理由\"}。"
                  "全行を出力すること。\n\n" + body)
        opt = ClaudeAgentOptions(model="claude-sonnet-5-5", tools=[], setting_sources=[], extra_args={"strict-mcp-config": None}, max_turns=2, cwd="/tmp/exp-slide/empty")
        text = ""
        async with ClaudeSDKClient(opt) as c:
            await c.query(prompt)
            async for m in c.receive_response():
                if isinstance(m, AssistantMessage):
                    for b in m.content:
                        if hasattr(b, "text"): text += b.text
        m = re.search(r"\[.*\]", text, re.S)
        try: res = json.loads(m.group(0))
        except Exception: res = None
        return {"deck": str(deck), "lines": dict(lines), "judge": res, "raw": text if res is None else ""}

async def main():
    Path("/tmp/exp-slide/empty").mkdir(exist_ok=True)
    pats = sys.argv[2:]
    decks = []
    for p in pats: decks += sorted(OUT.glob(p))
    sem = asyncio.Semaphore(int(sys.argv[1]))
    res = await asyncio.gather(*[judge_one(d, sem) for d in decks])
    Path("/tmp/exp-slide/judged2_" + re.sub(r"[^A-Za-z0-9]+","_",pats[0]) + ".json").write_text(json.dumps(res, ensure_ascii=False, indent=1))
    for r in res:
        print(r["deck"], "FAILED" if r["judge"] is None else sum(1 for j in r["judge"] if j["labels"] and j["labels"] not in (["ok"], ["NA"])))
asyncio.run(main())
