"""Build the read-only review index from Markdown; reviewer drafts never write it back."""
from pathlib import Path
import csv,json,re
R=Path(__file__).parent
fields={'主题':'group','确认程度':'confirmation','优先级':'priority','覆盖':'coverage','页面':'screens','用例':'uc','来源':'source','验收ID':'acceptance_id','规则':'rule','验收':'acceptance','差距':'gap','责任角色':'owner'}
items=[]
for block in re.split(r'(?=^## REQ-)',(R/'requirements-review.md').read_text(),flags=re.M)[1:]:
 m=re.match(r'## (REQ-\S+) (.+)',block);item={'id':m[1],'title':m[2]}
 for line in block.splitlines()[1:]:
  m=re.match(r'- ([^：]+)：(.*)',line)
  if m and m[1] in fields:item[fields[m[1]]]=m[2]
 assert all(k in item for k in fields.values()),item['id'];items.append(item)
assert len({i['id'] for i in items})==len(items)
(R/'review-data.json').write_text(json.dumps({'version':'2026-09-11-r1','items':items},ensure_ascii=False,indent=2)+'\n')
with (R/'requirements.csv').open('w',newline='') as f:
 w=csv.DictWriter(f,fieldnames=items[0].keys(),lineterminator='\n');w.writeheader();w.writerows(items)
with (R/'traceability.csv').open('w',newline='') as f:
 w=csv.writer(f,lineterminator='\n');w.writerow(['requirement_id','screen_id','component_id','state_id','acceptance_id','evidence_path','coverage_status','owner','notes'])
 for i in items:
  evidence='../evidence/oura-slice-checks.json' if i['id'] in ['REQ-R08','REQ-R09','REQ-R15'] else ('../evidence/browser-checks.json' if i['id'].startswith('REQ-0') else '../evidence/workspace-v3-checks.json')
  if i['coverage']!='covered':evidence=i['source']
  w.writerow([i['id'],i['screens'],'COMP-'+i['id'],'STATE-'+i['id'],i['acceptance_id'],evidence,i['coverage'],i['owner'],i['gap']])
with (R/'component-states.csv').open('w',newline='') as f:
 w=csv.writer(f,lineterminator='\n');w.writerow(['component_id','state_id','screen_id','requirement_id','state_contract','current_evidence'])
 for i in items:w.writerow(['COMP-'+i['id'],'STATE-'+i['id'],i['screens'],i['id'],i['rule']+' '+i['acceptance'],i['coverage']+'; '+i['gap']])
names=['日历首页','餐次对齐详情','食动平衡','久坐与活动','AI建议与行动','补记与修正','演示设置与异常','我的/会员档案','PC会员总览','周期趋势','食动报告','习惯目标','分享授权','干预与跟进','健康数据问答','自动数据中心','身体状态巡检','Agent偏好','个人背景','睡眠入口/详情','当前状态依据','今日食动支持','阶段营养服务','全天身体回放','体检导入/报告领取','微体检详情','每日餐单/外卖选择','实际饮食与剩餐修订','膳食结构与阶段变化','医疗跟进任务','持续提醒与反馈','按需营养商品']
with (R/'screens.csv').open('w',newline='') as f:
 w=csv.writer(f,lineterminator='\n');w.writerow(['screen_id','name','status','entry','linked_requirements','role','state_note'])
 for n,name in enumerate(names,1):
  id=f'SCREEN-{n:02}';linked=';'.join(i['id'] for i in items if id in i['screens'].split(';'));w.writerow([id,name,'existing-demo' if n<=23 else 'planned-only','../prototype/pc.html' if n==9 else '../prototype/food-movement-calendar.html',linked,'营养师/教练' if n==9 else '本人/获授权专业人员','合成原型；部分只为容器或组件' if n<=23 else '无可点击实现；对应全量需求与UC'])
if not (R/'review-decisions.csv').exists():
 with (R/'review-decisions.csv').open('w',newline='') as f:
  w=csv.writer(f,lineterminator='\n');w.writerow(['decision_id','note_id','linked_ids','disposition','severity','decision','reason','owner','writeback_paths','status','evidence_path']);w.writerow(['DEC-R1-OPEN','','ALL','needs-decision','review','等待Jack本次评审','浏览器意见先导出再处理','Jack','','open','requirements-prototype-review.html'])
if not (R/'annotations.json').exists():
 (R/'annotations.json').write_text('{"version":"2026-09-11-r1","annotations":[],"status":"尚未收到本次人工评审意见；不覆盖浏览器本地草稿"}\n')
(R/'screens.json').write_text(json.dumps(list(csv.DictReader((R/'screens.csv').open())),ensure_ascii=False,indent=2)+'\n')
print('Built',len(items),'requirements,',len(names),'screens')
