#!/usr/bin/env python3
"""Inspect BVH declarations and sample widths; does not run or evaluate Kimodo.

Standard library only. This is an authored structural inspector, not a general
BVH parser, a forward-kinematics implementation, or a retargeting tool.
"""
import argparse
import collections
import hashlib
import json
from pathlib import Path
import re


def inspect(path):
    data = Path(path).read_bytes()
    text = data.decode("utf-8")
    hierarchy, motion = re.split(r"^MOTION\s*$", text, maxsplit=1, flags=re.M)
    nodes = re.findall(r"^\s*(ROOT|JOINT)\s+(\S+)", hierarchy, re.M)
    channel_counts = [int(v) for v in re.findall(r"^\s*CHANNELS\s+(\d+)", hierarchy, re.M)]
    lines = [line.strip() for line in motion.splitlines() if line.strip()]
    declared_frames = int(re.fullmatch(r"Frames:\s*(\d+)", lines[0]).group(1))
    frame_time = float(re.fullmatch(r"Frame Time:\s*(\S+)", lines[1]).group(1))
    samples = [[float(value) for value in line.split()] for line in lines[2:]]
    expected_width = sum(channel_counts)
    return {
        "byte_count": len(data),
        "sha256": hashlib.sha256(data).hexdigest(),
        "root_names": [name for kind, name in nodes if kind == "ROOT"],
        "joint_declarations": sum(kind == "JOINT" for kind, name in nodes),
        "total_named_bvh_nodes": len(nodes),
        "channel_declaration_count": len(channel_counts),
        "channel_count_histogram": dict(sorted(collections.Counter(channel_counts).items())),
        "total_channels_per_frame": expected_width,
        "declared_frames": declared_frames,
        "observed_frames": len(samples),
        "frame_time_seconds": frame_time,
        "sample_rate_hz": 1.0 / frame_time,
        "observed_frame_widths": sorted(set(len(sample) for sample in samples)),
        "checks": {
            "node_and_channel_declaration_counts_match": len(nodes) == len(channel_counts),
            "declared_frames_match_rows": declared_frames == len(samples),
            "every_row_matches_channel_sum": all(len(sample) == expected_width for sample in samples),
        },
    }


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("path", help="Path to a downloaded BVH file")
    parser.add_argument("--source-url", help="Exact public source URL, recorded as supplied")
    args = parser.parse_args()
    report = inspect(args.path)
    if args.source_url:
        report["source_url"] = args.source_url
    report["method"] = "Read text declarations and numeric rows only; no model, DCC, or game-engine execution"
    print(json.dumps(report, indent=2))
