#!/usr/bin/env python3
"""Reproduce the five synthetic worked examples. No network or external packages."""
from pathlib import Path
from collections import defaultdict
from decimal import Decimal
import csv, json
ROOT = Path(__file__).resolve().parent

def read(name):
    with (ROOT/name).open(encoding='utf-8-sig',newline='') as f:
        return list(csv.DictReader(f))

def pct(a,b):
    if not b:
        raise ValueError('Zero denominator: the result is undefined, not 0 or 100%.')
    return Decimal(a)/Decimal(b)*100

fill=read('example-01-fill-input.csv')
orders=defaultdict(list)
for r in fill: orders[r['order_id']].append(r)
line_fill=pct(sum(int(r['fulfilled_units'])>=int(r['requested_units']) for r in fill),len(fill))
unit_fill=pct(sum(min(int(r['fulfilled_units']),int(r['requested_units'])) for r in fill),sum(int(r['requested_units']) for r in fill))
order_fill=pct(sum(all(int(r['fulfilled_units'])>=int(r['requested_units']) for r in rows) for rows in orders.values()),len(orders))
assert len(fill)==1000 and len(orders)==100 and (line_fill,unit_fill,order_fill)==(99,99,90)

perfect=read('example-02-perfect-order-input.csv')
flags=('on_time','complete','damage_free','documentation_correct')
perfect_results={}
for scenario in ('shared_failures','disjoint_failures'):
    rows=[r for r in perfect if r['scenario']==scenario]
    rates={f:Decimal(sum(int(r[f]) for r in rows))/len(rows) for f in flags}
    assert all(v==Decimal('0.95') for v in rates.values())
    observed=pct(sum(all(int(r[f]) for f in flags) for r in rows),len(rows))
    composite=Decimal(100)
    for rate in rates.values(): composite*=rate
    assert composite==Decimal('81.450625')
    assert observed==(95 if scenario=='shared_failures' else 80)
    perfect_results[scenario]={'component_percent':{k:str(v*100) for k,v in rates.items()},'observed_perfect_percent':str(observed),'component_index_percent':str(composite)}

inv=read('example-03-inventory-input.csv')
aggregate=pct(sum(int(r['system_units']) for r in inv),sum(int(r['counted_units']) for r in inv))
exact=pct(sum(int(r['system_units'])==int(r['counted_units']) for r in inv),len(inv))
assert (aggregate,exact)==(100,0)

labor=read('example-04-labor-input.csv')
assert len({r['common_shift_elapsed_hours'] for r in labor})==1
lines=sum(int(r['completed_pick_lines']) for r in labor)
people_hours=sum(int(r['person_hours']) for r in labor)
elapsed=Decimal(labor[0]['common_shift_elapsed_hours'])
throughput=Decimal(lines)/elapsed
productivity=Decimal(lines)/people_hours
assert (lines,people_hours,throughput,productivity)==(1200,24,150,50)

docks=read('example-05-dock-input.csv')
final=[r for r in docks if int(r['hour_of_shift'])==max(int(x['hour_of_shift']) for x in docks)]
snapshot=pct(sum(int(r['occupied_at_hour_end']) for r in final),len(final))
time_share=pct(sum(int(r['productive_hours']) for r in docks),sum(int(r['scheduled_hours']) for r in docks))
assert (snapshot,time_share)==(100,50)

results={'status':'PASS','data_type':'All example inputs are synthetic illustrations, not observations',
 'E01':{'line_fill_percent':str(line_fill),'unit_fill_percent':str(unit_fill),'order_fill_percent':str(order_fill)},
 'E02':perfect_results,'E03':{'aggregate_quantity_ratio_percent':str(aggregate),'exact_match_percent':str(exact)},
 'E04':{'lines_per_elapsed_hour':str(throughput),'lines_per_person_hour':str(productivity)},
 'E05':{'snapshot_occupancy_percent':str(snapshot),'productive_time_share_percent':str(time_share)}}

# Additional constructed scenarios discussed in the article.
alternative_fill=[dict(r) for r in fill]
first_order=alternative_fill[0]['order_id']
for r in alternative_fill:
    r['fulfilled_units']='0' if r['order_id']==first_order else r['requested_units']
alt_groups=defaultdict(list)
for r in alternative_fill: alt_groups[r['order_id']].append(r)
alt_line=pct(sum(int(r['fulfilled_units'])>=int(r['requested_units']) for r in alternative_fill),len(alternative_fill))
alt_order=pct(sum(all(int(r['fulfilled_units'])>=int(r['requested_units']) for r in rr) for rr in alt_groups.values()),len(alt_groups))
assert (alt_line,alt_order)==(99,99)
four_people_lines=lines+400
four_people_hours=people_hours+8
assert Decimal(four_people_lines)/elapsed==200
assert Decimal(four_people_lines)/four_people_hours==50
results['additional_checks']={'all_ten_misses_on_one_order':{'line_fill_percent':str(alt_line),'order_fill_percent':str(alt_order)},'fourth_picker_same_400_lines_and_8_hours':{'lines_per_elapsed_hour':'200','lines_per_person_hour':'50'}}

(ROOT/'reproduced-results.json').write_text(json.dumps(results,indent=2),encoding='utf-8')
print(json.dumps(results,indent=2))
