import json,os,subprocess,sys,re,concurrent.futures as cf
ROOT='/tmp/aire'; TASKS=ROOT+'/tasks'
ASK_LINE="実装の前に、確認したいことがあれば先に質問してください。"
ASK_LINE_E="実装の前に、確認したいことがあれば先に質問してください。入力の例外や不正値、業務上の決まりごと、出力の細部(並び順や形式)、エラー時の振る舞いのうち、私がまだ決めていないことを洗い出してください。"
def sh(args,cwd,inp=''):
    try:
        r=subprocess.run(args,cwd=cwd,capture_output=True,text=True,input=inp,timeout=1500)
        return r.stdout
    except subprocess.TimeoutExpired as e:
        return (e.stdout or b'').decode() if isinstance(e.stdout,bytes) else (e.stdout or '')
def claude(prompt,cwd,tools=True,resume=None):
    a=['claude','-p',prompt,'--setting-sources','','--output-format','stream-json','--verbose']
    if tools: a+=['--dangerously-skip-permissions','--allowedTools','Write,Read,Bash']
    else: a+=['--tools','']
    if resume: a+=['--resume',resume]
    out=sh(a,cwd)
    res=None;tools_used=[]
    for l in out.splitlines():
        try: j=json.loads(l)
        except Exception: continue
        if j.get('type')=='result': res=j
        if j.get('type')=='assistant':
            for c in j['message'].get('content',[]):
                if c.get('type')=='tool_use': tools_used.append({'name':c['name'],'input':c['input']})
    return res,tools_used,out
def one(task,cond,i):
    L=f'{ROOT}/runs/{task}_{cond}_{i}'   # ログ置き場(作業フォルダの外。試行後に書く)
    if os.path.exists(L+'/score.json'): return
    D=f'{ROOT}/w/{task}_{cond}_{i}/work'  # 作業フォルダ。親には他に何も無い
    import shutil; shutil.rmtree(f'{ROOT}/w/{task}_{cond}_{i}',ignore_errors=True)
    os.makedirs(D,exist_ok=True); os.makedirs(L,exist_ok=True)
    base=open(f'{TASKS}/{task}.base').read().strip(); spec=open(f'{TASKS}/{task}.spec').read().strip()
    meta={}
    if cond=='A':
        res,tu,raw=claude(base,D)
    elif cond=='C':
        res,tu,raw=claude(base+'\n\n'+spec,D)
    else: # B, D, E
        r1,tu1,raw1=claude(base+'\n\n'+(ASK_LINE_E if cond=='E' else ASK_LINE),D)
        q=(r1 or {}).get('result','')
        meta['stage1_files']=sorted(f for f in os.listdir(D) if f.endswith('.py'))
        if cond in 'BE':
            req=("あなたは依頼主です。下の隠れた要件だけを知っています。開発者からの質問に、隠れた要件に関係するものだけ簡潔に答えてください。聞かれていない要件は絶対に漏らさないでください。要件に無いことを聞かれたら『特にこだわりなし、お任せ』と答えてください。"
                 "回答の最後に、質問が触れた隠れた要件の番号を `HIT: 1,3` の形式で1行だけ書いてください(無ければ `HIT: none`)。\n\n"+spec+"\n\n## 開発者の質問\n"+q)
            rq,_,_=claude(req,ROOT+'/requester_cwd',tools=False)
            ans=(rq or {}).get('result','')
        else:
            ans="すべて、お任せします。特にこだわりはありません。\nHIT: none"
        open(L+'/questions.txt','w').write(q); open(L+'/answers.txt','w').write(ans)
        shown=re.sub(r'\n?HIT:.*$','',ans).strip()
        sid=(r1 or {}).get('session_id')
        res,tu2,raw2=claude("回答します。\n\n"+shown+"\n\nこの内容で実装してください。",D,resume=sid)
        tu=tu1+tu2; raw=raw1+'\n'+raw2
    open(L+'/stream.jsonl','w').write(raw)
    open(L+'/final.txt','w').write((res or {}).get('result',''))
    meta['files']=sorted(os.listdir(D))
    meta['model']=list(((res or {}).get('modelUsage') or {}).keys())
    meta['cost']=(res or {}).get('total_cost_usd')
    meta['tools']=[(t['name'],t['input'].get('file_path') or t['input'].get('command','')[:300]) for t in tu]
    json.dump(meta,open(L+'/meta.json','w'),ensure_ascii=False)
    sc=subprocess.run(['python3',ROOT+'/score.py',task,D],capture_output=True,text=True).stdout
    shutil.copy(D+f'/{task}.py',L+f'/{task}.py') if os.path.exists(D+f'/{task}.py') else None
    open(L+'/score.json','w').write(sc)
if __name__=='__main__':
    os.makedirs(ROOT+'/requester_cwd',exist_ok=True)
    jobs=[(t,c,i) for i in range(1,6) for t in ('warikan','points','booking') for c in sys.argv[1]]
    def safe(a):
        try: one(*a)
        except Exception as e: print('ERR',a,e,flush=True)
    with cf.ThreadPoolExecutor(6) as ex:
        list(ex.map(safe,jobs))
