"""Validate completed UTF-8 JSONL input without changing it. Python 3.9+."""
import argparse
import json
from pathlib import Path
import sys


def line_limit(value):
    number = int(value)
    if not 1 <= number <= 16 * 1024 * 1024:
        raise argparse.ArgumentTypeError("max-line-bytes must be 1..16777216")
    return number


def reject_constant(value):
    raise ValueError(f"non-JSON number token: {value}")


def unique_object(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError(f"duplicate object key: {key!r}")
        result[key] = value
    return result


def audit(path, max_line_bytes, objects):
    records = 0
    with path.open("rb") as file:
        while True:
            raw = file.readline(max_line_bytes + 1)
            if not raw:
                break
            number = records + 1
            try:
                if len(raw) > max_line_bytes:
                    raise ValueError(f"line exceeds {max_line_bytes} bytes")
                text = raw.decode("utf-8", errors="strict")
                if not text.strip():
                    raise ValueError("blank line is not a JSON value")
                value = json.loads(
                    text,
                    parse_constant=reject_constant,
                    object_pairs_hook=unique_object,
                )
                if objects and not isinstance(value, dict):
                    raise ValueError("expected a JSON object")
            except json.JSONDecodeError as exc:
                raise ValueError(
                    f"line {number}, column {exc.colno}: {exc.msg}"
                ) from exc
            except (ValueError, RecursionError) as exc:
                raise ValueError(f"line {number}: {exc}") from exc
            records += 1
    return {"file": str(path), "records": records, "valid": True}


def main():
    parser = argparse.ArgumentParser(description=__doc__, allow_abbrev=False)
    parser.add_argument("file", type=Path, help="completed, unchanging JSONL file")
    parser.add_argument("--objects", action="store_true", help="require object records")
    parser.add_argument(
        "--max-line-bytes", type=line_limit, default=1024 * 1024,
        help="physical line byte limit, including LF/CRLF (default: 1048576)",
    )
    args = parser.parse_args()
    try:
        result = audit(args.file, args.max_line_bytes, args.objects)
    except (OSError, ValueError) as exc:
        print(f"ERROR: {args.file}: {exc}", file=sys.stderr)
        return 1
    print(json.dumps(result, ensure_ascii=False))
    return 0


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