"""Compare two CBOMkit runs and CRYPTAGION's published CBOM for pyca/cryptography @ d45b7930."""
import json, re, sys, collections
from pathlib import Path
from jsonschema import Draft7Validator
from referencing import Registry, Resource

SP = Path(sys.argv[1]); REPO = Path(sys.argv[2])
schemas = SP / "evidence/schemas"
res = []
for f in schemas.glob("*.json"):
    o = json.loads(f.read_text())
    if "$id" in o: res.append((o["$id"], Resource.from_contents(o)))
reg = Registry().with_resources(res)
schema = json.loads((schemas / "bom-1.6.schema.json").read_text())
UUID = re.compile(r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")

def load(p): return json.loads(Path(p).read_text())
def errors(c): return [e.message for e in Draft7Validator(schema, registry=reg).iter_errors(c)]

def norm_kit(c):
    refmap = {}
    out = []
    for comp in c["components"]:
        d = json.loads(json.dumps(comp))
        d.pop("bom-ref", None)
        d["name"] = UUID.sub("<id>", d["name"])
        s = json.dumps(d, sort_keys=True)
        s = UUID.sub("<id>", s)
        out.append(s)
    return sorted(out)

k1, k2 = load(SP / "run/out1/cbomkit-cbom.json"), load(SP / "run/out2/cbomkit-cbom.json")
ours = load(REPO / "samples/pyca-cryptography/2026-10-10/cbom.json")
r = {}
r["cbomkit_schema_errors"] = [len(errors(k1)), len(errors(k2))]
r["cbomkit_schema_error_samples"] = errors(k1)[:5]
r["ours_schema_errors"] = len(errors(ours))
r["cbomkit_repeat_identical"] = norm_kit(k1) == norm_kit(k2)
r["cbomkit_components"] = len(k1["components"])
r["cbomkit_dependencies"] = len(k1.get("dependencies", []))
r["cbomkit_metadata"] = k1["metadata"].get("properties")

def occ(comp):
    return [(o.get("location"), o.get("line")) for o in comp.get("evidence", {}).get("occurrences", [])]

def scope_of(path):
    if path.startswith("src/"): return "library source"
    if path.startswith("tests/") or path.startswith("vectors/"): return "tests and vectors"
    if path.startswith("docs/"): return "docs"
    return "other"

kit_occ = []
for comp in k1["components"]:
    ap = comp.get("cryptoProperties", {})
    for loc, line in occ(comp):
        kit_occ.append({"name": UUID.sub("<id>", comp["name"]), "assetType": ap.get("assetType"),
                        "primitive": ap.get("algorithmProperties", {}).get("primitive"),
                        "location": loc, "line": line})
r["cbomkit_occurrences"] = len(kit_occ)
r["cbomkit_by_scope"] = collections.Counter(scope_of(o["location"]) for o in kit_occ)
r["cbomkit_by_asset_type"] = collections.Counter(o["assetType"] for o in kit_occ)
r["cbomkit_names"] = collections.Counter(o["name"] for o in kit_occ).most_common()
r["cbomkit_languages"] = collections.Counter(Path(o["location"]).suffix for o in kit_occ)
r["cbomkit_files"] = sorted({o["location"] for o in kit_occ})
r["cbomkit_algorithm_params"] = sorted({json.dumps(c.get("cryptoProperties", {}).get("algorithmProperties", {}), sort_keys=True) for c in k1["components"] if c.get("cryptoProperties", {}).get("assetType") == "algorithm"})

our_occ = []
for comp in ours["components"]:
    sc = next((p["value"] for p in comp.get("properties", []) if p["name"] == "cryptagion:source:scope"), None)
    for loc, line in occ(comp):
        our_occ.append({"name": comp["name"], "location": loc, "line": line, "scope": sc})
r["ours_occurrences"] = len(our_occ)
r["ours_by_scope"] = collections.Counter(o["scope"] for o in our_occ)
r["ours_languages"] = collections.Counter(Path(o["location"]).suffix for o in our_occ)

kit_lines = {(o["location"], o["line"]) for o in kit_occ}
our_lines = {(o["location"], o["line"]) for o in our_occ}
r["line_overlap"] = len(kit_lines & our_lines)
r["kit_only_lines"] = sorted(kit_lines - our_lines)
kit_src = {o["location"] for o in kit_occ if o["location"].startswith("src/")}
our_src = {o["location"] for o in our_occ if o["location"].startswith("src/")}
r["src_files_both"] = sorted(kit_src & our_src)
r["src_files_kit_only"] = sorted(kit_src - our_src)
r["src_files_ours_only"] = sorted(our_src - kit_src)
r["kit_src_occurrences"] = [o for o in kit_occ if o["location"].startswith("src/")]
r["our_src_occurrences_in_kit_files"] = [o for o in our_occ if o["location"] in kit_src]
r["kit_non_python"] = [o for o in kit_occ if not o["location"].endswith(".py")]
print(json.dumps(r, indent=1, default=list))
(SP / "run/analysis.json").write_text(json.dumps(r, indent=1, default=list))
