# Python 3.10+, standard library only. Input is audited customer-level CSV.
import csv, sys, json
from fractions import Fraction as F
from decimal import Decimal, localcontext, ROUND_HALF_UP

def display(value, places=2):
    if value is None:
        return 'N/A'
    with localcontext() as ctx:
        ctx.prec = 40
        n = Decimal(value.numerator) / Decimal(value.denominator)
        return str(n.quantize(Decimal(1).scaleb(-places), rounding=ROUND_HALF_UP))

if len(sys.argv) != 5:
    raise SystemExit('usage: python3 check_customer_mrr.py FILE ACCOUNT MODE CURRENCY')
file, account, mode, currency = sys.argv[1:]
rows = []
seen = set()
required = {'account_id','mode','customer_id','currency','opening_mrr_minor',
            'closing_mrr_minor','source_ref'}
with open(file, newline='', encoding='utf-8-sig') as handle:
    reader = csv.DictReader(handle)
    if not required <= set(reader.fieldnames or []):
        raise ValueError('missing columns')
    for row in reader:
        if row['account_id'] != account or row['mode'] != mode:
            raise ValueError('wrong account or mode')
        if not row['customer_id'] or not row['source_ref'].strip():
            raise ValueError('missing customer ID or source reference')
        key = (row['customer_id'], row['currency'])
        if key in seen:
            raise ValueError('duplicate customer-currency row')
        seen.add(key)
        # Blank, NaN and unknown amounts fail; never replace with zero.
        b = F(row['opening_mrr_minor'])
        e = F(row['closing_mrr_minor'])
        if b < 0 or e < 0:
            raise ValueError('MRR cannot be negative in this contract')
        if row['currency'] == currency:
            rows.append((row['customer_id'], b, e))
if not rows:
    raise ValueError('no rows for requested currency')
cohort = [(c,b,e) for c,b,e in rows if b > 0]
begin = sum((b for _,b,_ in rows), F(0))
end = sum((e for _,_,e in rows), F(0))
lost = [c for c,_,e in cohort if e == 0]
retained = sum((e for _,_,e in cohort), F(0))
gross_retained = sum((min(b,e) for _,b,e in cohort), F(0))
print(json.dumps({
    'currency': currency, 'amount_unit': 'minor unit',
    'opening_mrr_minor_exact': str(begin), 'closing_mrr_minor_exact': str(end),
    'opening_customers': len(cohort),
    'closing_customers': sum(e > 0 for _,_,e in rows),
    'lost_customer_ids': lost,
    'logo_churn_percent': display(F(len(lost),len(cohort))*100) if cohort else 'N/A',
    'grr_percent': display(gross_retained/begin*100) if begin else 'N/A',
    'nrr_percent': display(retained/begin*100) if begin else 'N/A',
    'outside_opening_mrr_minor_exact': str(sum((e for _,b,e in rows if b==0),F(0))),
    'historical_event_counts_verified': False
}, ensure_ascii=False, indent=2))
