"""Deterministic teaching fixture. Python 3.10+, standard library only.

Run python generate.py [--output DIRECTORY]. Reads the adjacent inputs.json.
This computes already-established two-way tied pot awards; it is not a hand
evaluator, betting validator, general side-pot builder, or venue ruling tool.
"""
import argparse
import csv
import json
from pathlib import Path


def calculate(data):
    # Deliberately bounded to the declared fixture, including its pot formation.
    if data.get('schema') != 1:
        raise ValueError('Unsupported input schema')
    seats = data['seats']
    if seats != ['A', 'B', 'C', 'D', 'E']:
        raise ValueError('This study uses five fixed clockwise seats A through E')
    if data['contributions'] != dict(A=500, B=500, C=100, D=100, E=200):
        raise ValueError('The contribution fixture is fixed')
    if data['folded'] != ['E'] or data['main_eligible'] != ['A', 'B', 'C', 'D']:
        raise ValueError('The eligibility fixture is fixed')
    if data['pots'] != [dict(id='main', amount=500, winners=['A', 'B']),
                        dict(id='side', amount=900, winners=['A', 'B'])]:
        raise ValueError('Use the two established fixture pots')
    if not data['buttons'] or len(set(data['buttons'])) != len(data['buttons']):
        raise ValueError('Provide distinct button positions')
    if not data['units'] or len(set(data['units'])) != len(data['units']):
        raise ValueError('Provide distinct positive integer denominations')
    rows, totals = [], []
    for button in data['buttons']:
        if button not in seats:
            raise ValueError('Unknown button')
        for unit in data['units']:
            if type(unit) is not int or unit <= 0:
                raise ValueError('Denomination must be a positive integer')
            if any(v % unit for v in data['contributions'].values()):
                raise ValueError('Contributions must be representable in this denomination')
            awards = dict(A=0, B=0)
            for pot in data['pots']:
                first = min(pot['winners'], key=lambda p: (seats.index(p) - seats.index(button) - 1) % len(seats))
                whole_pairs, odd_units = divmod(pot['amount'] // unit, 2)
                base, remainder = whole_pairs * unit, odd_units * unit
                a = base + (remainder if first == 'A' else 0)
                b = base + (remainder if first == 'B' else 0)
                rows.append(dict(button=button, unit=unit, pot=pot['id'], amount=pot['amount'],
                                 first=first, base=base, remainder=remainder, award_A=a, award_B=b))
                awards['A'] += a
                awards['B'] += b
            totals.append(dict(button=button, unit=unit, **awards))
    return dict(schema=1, main=500, side=900, total=1400, rows=rows, totals=totals)


def main():
    here = Path(__file__).resolve().parent
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--output', type=Path, default=here)
    args = parser.parse_args()
    data = json.loads((here / 'inputs.json').read_text(encoding='utf-8'))
    result = calculate(data)
    args.output.mkdir(parents=True, exist_ok=True)
    if args.output.resolve() != here:
        (args.output / 'inputs.json').write_bytes((here / 'inputs.json').read_bytes())
    (args.output / 'results.json').write_text(json.dumps(result, indent=2) + '\n', encoding='utf-8', newline='\n')
    with (args.output / 'settlements.csv').open('w', encoding='utf-8', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=list(result['rows'][0]), lineterminator='\n')
        writer.writeheader()
        writer.writerows(result['rows'])
    print(f"Generated {len(result['rows'])} pot rows and {len(result['totals'])} hand totals")


if __name__ == '__main__':
    main()
