#!/usr/bin/env python3
"""AI くささ検証 段階1: 3 社に同じお題で文章を書かせ、JSONL に貯める（討論はしない・単体の呼び出しだけ）。

  python3 -I gen_texts.py --out texts-v1.jsonl                 # 実行計画だけ表示（既定。API は呼ばない）
  OPENROUTER_API_KEY=... python3 -I gen_texts.py --out texts-v1.jsonl --run --max-usd 10

- 条件: plain（お題だけ）／natural（お題＋instruction-natural-v1.md の 1 文）。
- 途中で止まっても、同じ --out で再実行すれば済んだ id を飛ばして続きから書く。
- 実行順は --seed で決定的に混ぜる（時間帯の影響が特定の社・お題に偏らないように）。
- 温度などの生成設定は渡さない（各社の既定のまま。本番の DebateCross と同じ）。
"""
import argparse
import json
import os
import random
import sys
import time
import urllib.request

HERE = os.path.dirname(os.path.abspath(__file__))
MODELS = ["anthropic/claude-sonnet-5.5", "openai/gpt-6.1-sol", "google/gemini-3.8-flash"]
CONDITIONS = ["plain", "natural"]
URL = "https://openrouter.ai/api/v1/chat/completions"


def plan(topics, repeat, seed):
    jobs = [(q, m, c, r) for q in topics for m in MODELS for c in CONDITIONS for r in range(repeat)]
    random.Random(seed).shuffle(jobs)
    return jobs


def call(model, content, key, max_tokens):
    body = json.dumps({"model": model, "messages": [{"role": "user", "content": content}],
                       "max_tokens": max_tokens, "usage": {"include": True}}).encode()
    req = urllib.request.Request(URL, data=body, headers={"Authorization": f"Bearer {key}",
                                                         "Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=180) as res:
        return json.load(res)


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--topics", default=os.path.join(HERE, "topics-ai-style-v1.jsonl"))
    ap.add_argument("--instruction", default=os.path.join(HERE, "instruction-natural-v1.md"))
    ap.add_argument("--out", required=True)
    ap.add_argument("--repeat", type=int, default=5)
    ap.add_argument("--seed", type=int, default=20261101)
    ap.add_argument("--max-tokens", type=int, default=3000)
    ap.add_argument("--max-usd", type=float, default=10.0)
    ap.add_argument("--run", action="store_true")
    a = ap.parse_args()

    topics = [json.loads(l) for l in open(a.topics, encoding="utf-8") if l.strip()]
    instruction = open(a.instruction, encoding="utf-8").read().strip()
    jobs = plan(topics, a.repeat, a.seed)
    done = set()
    if os.path.exists(a.out):
        done = {json.loads(l)["id"] for l in open(a.out, encoding="utf-8") if l.strip()}
    print(f"お題 {len(topics)} × 社 {len(MODELS)} × 条件 {len(CONDITIONS)} × {a.repeat} 回 = {len(jobs)} 本"
          f"（済み {len(done)}・残り {len(jobs) - len(done & {self_id(*j) for j in jobs})}）")
    if not a.run:
        print("--run を付けると実行します（API の利用料がかかります）。")
        return
    key = os.environ.get("OPENROUTER_API_KEY") or sys.exit("OPENROUTER_API_KEY が未設定")
    spent = 0.0
    with open(a.out, "a", encoding="utf-8") as f:
        for q, m, c, r in jobs:
            jid = self_id(q, m, c, r)
            if jid in done:
                continue
            if spent >= a.max_usd:
                sys.exit(f"上限 ${a.max_usd} に達したので止めます（${spent:.3f}）")
            content = q["prompt"] + ("\n\n" + instruction if c == "natural" else "")
            t0 = time.time()
            for attempt in range(3):
                try:
                    res = call(m, content, key, a.max_tokens)
                    break
                except Exception as e:  # noqa: BLE001 — 失敗は 2 回まで同じ条件でやり直す
                    err = str(e)
                    time.sleep(5 * (attempt + 1))
            else:
                print(f"失敗: {jid} {err}")
                continue
            ch = res["choices"][0]
            usage = res.get("usage") or {}
            spent += float(usage.get("cost") or 0)
            f.write(json.dumps({
                "id": jid, "questionId": q["questionId"], "genre": q["genre"], "model": m, "condition": c,
                "runIndex": r, "text": ch["message"].get("content") or "", "finishReason": ch.get("finish_reason"),
                "servedModel": res.get("model"), "provider": res.get("provider"),
                "inputTokens": usage.get("prompt_tokens"), "outputTokens": usage.get("completion_tokens"),
                "costUsd": usage.get("cost"), "elapsedMs": int((time.time() - t0) * 1000),
                "at": time.strftime("%Y-%m-%dT%H:%M:%S%z"),
            }, ensure_ascii=False) + "\n")
            f.flush()
            print(f"{jid} {ch.get('finish_reason')} ${spent:.3f}")


def self_id(q, m, c, r):
    return f"{q['questionId']}|{m}|{c}|{r}"


if __name__ == "__main__":
    main()
