"""Recompute public candidate CI from the archived directed pedestrian times."""
import csv,collections,math
from pathlib import Path
def read(name):
 with Path(name).open(encoding='utf-8-sig',newline='') as f:return list(csv.DictReader(f))
def main():
 candidates=read('candidates.csv');neighbors=read('competition_neighbors.csv');groups=collections.defaultdict(list)
 for n in neighbors:groups[n['shop_id']].append(n)
 out=[]
 for c in candidates:
  ns=groups[c['shop_id']];assert len({n['competitor_id'] for n in ns})==len(ns)
  row={'shop_id':c['shop_id']}
  for T in (3,5,10):
   missing=any(not n['walk_s'] and float(n['straight_m'])*3.6/6<T*60 for n in ns)
   total=None if missing else sum(max(0,1-float(n['walk_s'])/(60*T)) for n in ns if n['walk_s'])
   expected=c[f'ci_{T}min'];assert (total is None)==(expected=='')
   if total is not None:assert math.isclose(total,float(expected),abs_tol=.00011),(c['shop_id'],T,total,expected)
   row[f'ci_{T}min']=round(total,4) if total is not None else None
  out.append(row)
 with Path('competition_recomputed.csv').open('w',encoding='utf-8-sig',newline='') as f:
  writer=csv.DictWriter(f,fieldnames=['shop_id','ci_3min','ci_5min','ci_10min']);writer.writeheader();writer.writerows(out)
 print(f'PASS: {len(out)} candidate stores, 3 thresholds; all published CI values reproduced.')
if __name__=='__main__':main()
