"""Python 3, standard library only. Run: python calculate-report.py report-example.csv"""
import csv,json,sys
from decimal import Decimal,InvalidOperation,ROUND_HALF_UP
from pathlib import Path

def calculate(path):
    groups={};seen=set()
    with Path(path).open(encoding='utf-8-sig',newline='') as file:
        reader=csv.DictReader(file)
        required={'period','channel','spend_rub','leads','qualified_leads','paid_orders'}
        if set(reader.fieldnames or [])!=required:raise ValueError('Unexpected columns')
        for line,row in enumerate(reader,2):
            period,channel=row['period'].strip(),row['channel'].strip()
            if period not in {'before','after'} or not channel:raise ValueError(f'Invalid period/channel at line {line}')
            key=(period,channel)
            if key in seen:raise ValueError(f'Duplicate period/channel at line {line}')
            seen.add(key)
            try:
                amount=Decimal(row['spend_rub'])
                counts=[int(row[k]) for k in ['leads','qualified_leads','paid_orders']]
            except (InvalidOperation,ValueError):raise ValueError(f'Invalid number at line {line}') from None
            if not amount.is_finite() or amount<0 or min(counts)<0:raise ValueError(f'Negative or non-finite value at line {line}')
            leads,qualified,paid=counts
            if not paid<=qualified<=leads:raise ValueError(f'Invalid funnel counts at line {line}')
            item=groups.setdefault(period,{'spend_rub':Decimal(0),'leads':0,'qualified_leads':0,'paid_orders':0})
            for k,v in zip(item,[amount,leads,qualified,paid]):item[k]+=v
    if set(groups)!={'before','after'}:raise ValueError('Both periods are required')
    if {c for p,c in seen if p=='before'}!={c for p,c in seen if p=='after'}:raise ValueError('Channels must match between periods')
    def ratio(a,b):return str((Decimal(a)/Decimal(b)).quantize(Decimal('0.01'),rounding=ROUND_HALF_UP)) if b else None
    for item in groups.values():
        item['cost_per_lead']=ratio(item['spend_rub'],item['leads'])
        item['cost_per_qualified_lead']=ratio(item['spend_rub'],item['qualified_leads'])
        item['cost_per_paid_order']=ratio(item['spend_rub'],item['paid_orders'])
        item['spend_rub']=str(item['spend_rub'])
    return groups

if __name__=='__main__':
    try:print(json.dumps(calculate(sys.argv[1] if len(sys.argv)>1 else Path(__file__).with_name('report-example.csv')),ensure_ascii=False,indent=2))
    except (OSError,ValueError) as error:raise SystemExit('Input error: '+str(error))
