"""Compare two CSV exports and report what was added, removed, and changed.

Usage:
    python csv_compare.py yesterday.csv today.csv

Matches rows by a unique id column, detects additions, removals, and changed
fields, writes output/added.csv, output/removed.csv, output/changed.csv, and
prints a short summary. Neither input file is modified.
"""

import csv
import sys
from pathlib import Path

# --- Configure how records are matched and compared -------------------------
ID_COLUMN = "device_id"                              # the unique key in each row
COMPARE_COLUMNS = ["status", "owner", "location"]    # fields watched for changes


def load_rows(path):
    """Read a CSV into a list of dict records, one per row."""
    with open(path, newline="", encoding="utf-8") as f:
        return list(csv.DictReader(f))


def require_columns(rows, columns, source):
    """Stop early with a clear message if a needed column is missing."""
    present = set(rows[0].keys()) if rows else set()
    missing = [c for c in columns if c not in present]
    if missing:
        print(f"{source} is missing required column(s): {', '.join(missing)}")
        raise SystemExit(1)


def index_by_id(rows, id_column):
    """Key each row by its unique id. Warn on duplicates (last row wins)."""
    by_id = {}
    for row in rows:
        key = row[id_column]
        if key in by_id:
            print(f"Warning: duplicate {id_column} {key!r}; keeping the last row.")
        by_id[key] = row
    return by_id


def compare(old, new, columns):
    """Return (added, removed, changed) records given two id->row dicts."""
    added = [new[i] for i in new.keys() - old.keys()]      # ids only today has
    removed = [old[i] for i in old.keys() - new.keys()]    # ids only yesterday had

    changed = []
    for i in old.keys() & new.keys():                      # ids in both files
        before, after = old[i], new[i]
        if any(before.get(c) != after.get(c) for c in columns):
            changed.append(after)
    return added, removed, changed


def write_reports(groups, out_dir, fieldnames):
    """Write one CSV per category ({name: rows}) into out_dir."""
    out_dir.mkdir(parents=True, exist_ok=True)
    for name, rows in groups.items():
        with open(out_dir / f"{name}.csv", "w", newline="", encoding="utf-8") as f:
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            writer.writerows(rows)


def main():
    if len(sys.argv) < 3:
        print("Usage: python csv_compare.py <yesterday.csv> <today.csv>")
        raise SystemExit(1)

    old_path, new_path = Path(sys.argv[1]), Path(sys.argv[2])
    try:
        old_rows = load_rows(old_path)
        new_rows = load_rows(new_path)
    except FileNotFoundError as err:
        print(f"No such file: {err.filename}")
        raise SystemExit(1)

    needed = [ID_COLUMN] + COMPARE_COLUMNS
    require_columns(old_rows, needed, old_path)
    require_columns(new_rows, needed, new_path)

    old = index_by_id(old_rows, ID_COLUMN)
    new = index_by_id(new_rows, ID_COLUMN)
    added, removed, changed = compare(old, new, COMPARE_COLUMNS)

    out_dir = Path("output")
    fieldnames = list(new_rows[0].keys()) if new_rows else needed
    write_reports(
        {"added": added, "removed": removed, "changed": changed},
        out_dir, fieldnames)

    print("Comparison complete.\n")
    print(f"Added records: {len(added)}")
    print(f"Removed records: {len(removed)}")
    print(f"Changed records: {len(changed)}\n")
    print("Reports written to:")
    for name in ("added", "removed", "changed"):
        print(f"- output/{name}.csv")


if __name__ == "__main__":
    main()
