#!/usr/bin/env python3
"""Convert an array of flat JSON objects to CSV without network access."""

from __future__ import annotations

import argparse
import csv
import json
from pathlib import Path
from typing import Any


def _load_rows(path: Path) -> list[dict[str, Any]]:
    try:
        value = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, UnicodeError, json.JSONDecodeError) as exc:
        raise ValueError(f"could not read valid JSON from {path}: {exc}") from exc
    if not isinstance(value, list) or not value:
        raise ValueError("input must be a non-empty JSON array of flat objects")
    rows: list[dict[str, Any]] = []
    for index, item in enumerate(value, start=1):
        if not isinstance(item, dict):
            raise ValueError(f"row {index} is not a JSON object")
        for key, cell in item.items():
            if not isinstance(key, str):
                raise ValueError(f"row {index} contains a non-string key")
            if isinstance(cell, (dict, list)):
                raise ValueError(f"row {index} field {key!r} is nested; only flat objects are supported")
        rows.append(item)
    return rows


def convert(input_path: Path, output_path: Path) -> tuple[int, list[str]]:
    """Write *input_path* as CSV and return row count plus stable field order."""
    rows = _load_rows(input_path)
    fields: list[str] = []
    seen: set[str] = set()
    for row in rows:
        for key in row:
            if key not in seen:
                seen.add(key)
                fields.append(key)
    output_path.parent.mkdir(parents=True, exist_ok=True)
    with output_path.open("w", encoding="utf-8", newline="") as handle:
        writer = csv.DictWriter(handle, fieldnames=fields, extrasaction="ignore")
        writer.writeheader()
        for row in rows:
            writer.writerow({key: ("" if row.get(key) is None else row.get(key, "")) for key in fields})
    return len(rows), fields


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("input", type=Path, help="JSON file containing a non-empty array of flat objects")
    parser.add_argument("output", type=Path, help="CSV file to create")
    args = parser.parse_args()
    try:
        rows, fields = convert(args.input, args.output)
    except ValueError as exc:
        parser.error(str(exc))
    except OSError as exc:
        parser.error(f"could not write {args.output}: {exc}")
    print(f"wrote {rows} rows and {len(fields)} columns to {args.output}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
