"""Exact fixture arithmetic; Python 3 standard library. No player data or forecast."""
import csv
import io
import json
from fractions import Fraction as F
from pathlib import Path
import sys

def union_minutes(rows):
    intervals = sorted((r['start_min'], r['end_min']) for r in rows)
    total = 0
    start, end = intervals[0]
    for a, b in intervals[1:]:
        if a > end:
            total += end - start
            start, end = a, b
        else:
            end = max(end, b)
    return total + end - start

def calculate(case):
    rows = case['rows']
    if not rows or len({r['id'] for r in rows}) != len(rows):
        raise ValueError('Nonempty rows with unique IDs required')
    for r in rows:
        if F(r['big_blind_usd']) <= 0 or type(r['hands']) is not int or r['hands'] <= 0:
            raise ValueError('Positive big blind and positive integer hand count required')
        if any(type(r[k]) is not int for k in ('start_min','end_min')) or r['start_min'] < 0 or r['end_min'] <= r['start_min']:
            raise ValueError('Increasing nonnegative integer minutes required')
    detail = [dict(r, net_bb=str(F(r['net_usd']) / F(r['big_blind_usd'])), bb_per_100=str(100 * F(r['net_usd']) / F(r['big_blind_usd']) / r['hands'])) for r in rows]
    hands = sum(r['hands'] for r in rows)
    dollars = sum(F(r['net_usd']) for r in rows)
    bb = sum(F(r['net_bb']) for r in detail)
    hours = F(union_minutes(rows), 60)
    table_hours = sum(F(r['end_min']-r['start_min'],60) for r in rows)
    return {'id':case['id'], 'label':case['label'], 'rows':detail, 'total_hands':hands,
            **{k:str(v) for k,v in {'net_usd':dollars,'net_bb':bb,'elapsed_hours':hours,'table_hours':table_hours,
            'bb_per_100':100*bb/hands,'hands_per_hour':F(hands)/hours,'bb_per_hour':bb/hours,'usd_per_hour':dollars/hours,
            'unweighted_mean_bb_per_100':sum(F(r['bb_per_100']) for r in detail)/len(rows)}.items()}}

def main():
    here = Path(__file__).resolve().parent
    target = Path(sys.argv[1]) if len(sys.argv)>1 else here
    target.mkdir(parents=True, exist_ok=True)
    data = json.loads((here/'inputs.json').read_text(encoding='utf-8'))
    output = {'method':'Exact rational arithmetic; active elapsed time is the union of table intervals.', 'cases':[calculate(c) for c in data['cases']]}
    (target/'results.json').write_text(json.dumps(output,indent=2)+'\n',encoding='utf-8',newline='\n')
    stream = io.StringIO(newline='')
    writer = csv.writer(stream,lineterminator='\n')
    writer.writerow(['case','row','big_blind_usd','net_usd','hands','start_min','end_min','net_bb','bb_per_100'])
    for c in output['cases']:
        for r in c['rows']:
            writer.writerow([c['id']]+[r[k] for k in ['id','big_blind_usd','net_usd','hands','start_min','end_min','net_bb','bb_per_100']])
    (target/'sessions.csv').write_text(stream.getvalue(),encoding='utf-8',newline='\n')
    print('Generated 3 fixture cases, 6 rows (exact fractions in JSON/CSV).')

if __name__ == '__main__':
    main()
