import argparse
import csv
from io import StringIO
from pathlib import Path


def summarize(stream):
    reader = csv.DictReader(stream)
    if reader.fieldnames != ["category", "amount_toman"]:
        raise ValueError("Expected columns: category,amount_toman")
    totals = {}
    for line, row in enumerate(reader, start=2):
        category = (row.get("category") or "").strip()
        raw = (row.get("amount_toman") or "").strip()
        if None in row or not category:
            raise ValueError(f"Line {line}: missing category or extra column")
        try:
            amount = int(raw)
        except ValueError as error:
            raise ValueError(f"Line {line}: amount must be an integer") from error
        if amount < 0:
            raise ValueError(f"Line {line}: amount cannot be negative")
        totals[category] = totals.get(category, 0) + amount
    return totals


def self_test():
    assert summarize(StringIO("category,amount_toman\nfood,120000\nfood,80000\n")) == {"food": 200000}
    assert summarize(StringIO("category,amount_toman\n")) == {}
    for bad in ["food,nope", "food,-1", ",5", "food,5,extra"]:
        try:
            summarize(StringIO("category,amount_toman\n" + bad + "\n"))
        except ValueError:
            pass
        else:
            raise AssertionError("Invalid row was accepted: " + bad)
    print("Expenses: all checks passed")


def main():
    parser = argparse.ArgumentParser(description="Summarize expenses in toman")
    parser.add_argument("file", nargs="?", type=Path)
    parser.add_argument("--self-test", action="store_true")
    args = parser.parse_args()
    if args.self_test:
        self_test()
        return
    if args.file is None:
        parser.error("Provide a CSV file or --self-test")
    try:
        with args.file.open(encoding="utf-8-sig", newline="") as stream:
            totals = summarize(stream)
    except (OSError, ValueError) as error:
        parser.exit(1, f"Error: {error}\n")
    for category, amount in sorted(totals.items()):
        print(f"{category}: {amount:,} toman")
    print(f"TOTAL: {sum(totals.values()):,} toman")


if __name__ == "__main__":
    main()
