"""Local CSV example. Python 3.10+. Does not overwrite input or send data."""
import csv
import io
import json
import math
import sys
import unittest


def summarize(text):
    reader = csv.DictReader(io.StringIO(text), strict=True)
    if reader.fieldnames != ['group', 'value']:
        raise ValueError('Expected exactly group,value headers')
    groups = {}
    for line, row in enumerate(reader, 2):
        if None in row or row['value'] is None or not row['group'].strip():
            raise ValueError(f'Row {line}: expected group,value')
        raw = row['value'].strip()
        try:
            value = float(raw) if raw else None
            if value is not None and (not math.isfinite(value) or abs(value) > 1e9):
                raise ValueError()
        except ValueError:
            raise ValueError(f'Row {line}: invalid number') from None
        groups.setdefault(row['group'].strip(), []).append(value)
    def stats(values):
        valid = [v for v in values if v is not None]
        return dict(count=len(valid), missing=len(values)-len(valid),
                    mean=sum(valid)/len(valid) if valid else None)
    return dict(groups={k: stats(v) for k, v in groups.items()},
                total=stats([v for values in groups.values() for v in values]))


class Checks(unittest.TestCase):
    def test_capstone(self):
        r = summarize('group,value\nA,0\nA,6\nA,\nB,3\nB,9\n')
        self.assertEqual(r['total'], dict(count=4, missing=1, mean=4.5))
        self.assertEqual(r['groups']['A']['mean'], 3)
        self.assertEqual(r['groups']['B']['mean'], 6)
    def test_zero(self):
        self.assertEqual(summarize('group,value\nA,0\nA,4')['total']['mean'], 2)
    def test_empty(self):
        self.assertIsNone(summarize('group,value\n')['total']['mean'])
    def test_quoted(self):
        self.assertIn('Desk, A', summarize('group,value\n"Desk, A",4')['groups'])
    def test_malformed_quotes(self):
        with self.assertRaises(csv.Error): summarize('group,value\n"Desk, A,4')
    def test_invalid(self):
        for text in ['group,value\nA,oops', 'group,value\nA,nan', 'group,value\nA,inf',
                     'wrong,value\nA,2', 'group,value\nA,2,3', 'group,value\nA']:
            with self.assertRaises(ValueError): summarize(text)


if __name__ == '__main__':
    if len(sys.argv) == 2 and sys.argv[1] == '--test':
        unittest.main(argv=[sys.argv[0]])
    elif len(sys.argv) == 2:
        with open(sys.argv[1], encoding='utf-8-sig', newline='') as f:
            print(json.dumps(summarize(f.read()), ensure_ascii=False, indent=2, allow_nan=False))
    else:
        print('python3 data-summary.py --test\npython3 data-summary.py sample.csv')
