#!/usr/bin/env python3
"""Compare two QoR evidence directories."""

from __future__ import annotations

import argparse
import json
import sys
from datetime import datetime
from pathlib import Path
from typing import Any


def load_summary(path: Path) -> dict[str, Any]:
    manifest = path / "manifest.json" if path.is_dir() else path
    data = json.loads(manifest.read_text(encoding="utf-8"))
    return data.get("summary", {})


def delta_num(after: Any, before: Any) -> float | int | None:
    if after is None or before is None:
        return None
    return after - before


def fanout_index(summary: dict[str, Any]) -> dict[str, dict[str, Any]]:
    return {str(item.get("net")): item for item in summary.get("top_fanout", [])}


def compare(left: dict[str, Any], right: dict[str, Any]) -> dict[str, Any]:
    lt = left.get("timing", {})
    rt = right.get("timing", {})
    left_fanout = fanout_index(left)
    right_fanout = fanout_index(right)
    common_nets = sorted(set(left_fanout) & set(right_fanout))
    fanout_changes = []
    for net in common_nets[:20]:
        before = left_fanout[net]
        after = right_fanout[net]
        fanout_changes.append(
            {
                "net": net,
                "fanout_delta": delta_num(after.get("fanout"), before.get("fanout")),
                "slack_delta_ns": delta_num(after.get("worst_slack_ns"), before.get("worst_slack_ns")),
                "before": before,
                "after": after,
            }
        )
    return {
        "created_at": datetime.now().isoformat(timespec="seconds"),
        "timing_delta": {
            "wns_delta": delta_num(rt.get("wns"), lt.get("wns")),
            "tns_delta": delta_num(rt.get("tns"), lt.get("tns")),
            "failing_endpoints_delta": delta_num(rt.get("failing_endpoints"), lt.get("failing_endpoints")),
            "before": lt,
            "after": rt,
        },
        "fanout_changes": fanout_changes,
        "interpretation": interpret(lt, rt),
    }


def interpret(before: dict[str, Any], after: dict[str, Any]) -> str:
    bw = before.get("wns")
    aw = after.get("wns")
    bf = before.get("failing_endpoints")
    af = after.get("failing_endpoints")
    if bw is None or aw is None:
        return "incomplete_timing_data"
    if aw > bw and (af or 0) <= (bf or 0):
        return "timing_improved"
    if aw < bw or (af or 0) > (bf or 0):
        return "timing_regressed"
    return "timing_neutral"


def main(argv: list[str]) -> int:
    parser = argparse.ArgumentParser(description="Compare QoR evidence directories")
    parser.add_argument("before")
    parser.add_argument("after")
    parser.add_argument("--out", default=None)
    args = parser.parse_args(argv)

    result = compare(load_summary(Path(args.before).resolve()), load_summary(Path(args.after).resolve()))
    text = json.dumps(result, indent=2)
    if args.out:
        Path(args.out).write_text(text + "\n", encoding="utf-8")
    print(text)
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))
