#!/usr/bin/env python3
"""Summarize a weekly volunteer-hours CSV.

Usage: python3 weekly-report.py <file.csv>

Reads a CSV with columns `volunteer_id,hours` and writes <stem>-report.txt
next to the input. Blank hours are reported as warnings; any non-blank hours
value that is not a finite, non-negative number aborts the run (exit 1)
without writing a report, so bad data is never silently counted as zero.
"""

import csv
import shlex
import sys
from decimal import Decimal, InvalidOperation
from pathlib import Path


def fail(message):
    print(f"error: {message}", file=sys.stderr)
    sys.exit(1)


def parse_hours(raw, line_no, volunteer):
    try:
        value = Decimal(raw)
    except InvalidOperation:
        fail(f"line {line_no} ({volunteer}): invalid hours value {raw!r}")
    if not value.is_finite() or value < 0:
        fail(f"line {line_no} ({volunteer}): invalid hours value {raw!r}")
    return value


def main(argv):
    if len(argv) != 2:
        fail("usage: python3 weekly-report.py <file.csv>")

    in_path = Path(argv[1])
    if not in_path.is_file():
        fail(f"input file not found: {in_path}")

    out_path = in_path.with_name(f"{in_path.stem}-report.txt")

    with in_path.open(newline="", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        if not reader.fieldnames or "hours" not in reader.fieldnames:
            fail("CSV must have a header row with an 'hours' column")

        row_count = 0
        total = Decimal(0)
        warnings = []
        for row in reader:
            row_count += 1
            line_no = reader.line_num  # physical line in the file (header is line 1)
            volunteer = (row.get("volunteer_id") or "").strip() or "<no id>"
            raw = (row.get("hours") or "").strip()
            if raw == "":
                warnings.append(f"line {line_no} ({volunteer}): missing hours")
                continue
            total += parse_hours(raw, line_no, volunteer)

    script = Path(argv[0]).name
    rerun = f"python3 {shlex.quote(script)} {shlex.quote(str(in_path))}"

    lines = [
        f"Weekly report for {in_path.name}",
        "",
        f"Rows: {row_count}",
        f"Total hours (nonblank rows): {total}",
        "",
        f"Warnings ({len(warnings)}):",
    ]
    lines += [f"  - {w}" for w in warnings] or ["  (none)"]
    lines += [
        "",
        "To regenerate this report, run from the folder containing the script:",
        f"  {rerun}",
        f"This overwrites {out_path.name}; the input CSV is never modified.",
        "If any hours value is not a valid non-negative number, the script",
        "exits with an error naming the line and writes no report.",
    ]

    out_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
    print(f"wrote {out_path}")


if __name__ == "__main__":
    main(sys.argv)
