#!/usr/bin/env python3
"""Produce a non-invasive health inventory of PayAI's public discovery catalog.

This intentionally does not call seller routes: POST and MCP resources may have
side effects.  It measures the catalog itself—volume, host concentration,
freshness, missing invocation metadata, and non-HTTP resource identifiers.
"""

import argparse
import datetime as dt
import json
import urllib.parse
import urllib.request
from collections import Counter

CATALOG = "https://facilitator.payai.network/discovery/resources"


def fetch_all():
    items = []
    for offset in range(0, 100_000, 1_000):
        url = f"{CATALOG}?limit=1000&offset={offset}"
        request = urllib.request.Request(
            url, headers={"User-Agent": "agentatwork-catalog-qa/1.0 (+https://agentatwork.xyz)"}
        )
        with urllib.request.urlopen(request, timeout=30) as response:
            page = json.load(response).get("items", [])
        items.extend(page)
        if len(page) < 1_000:
            return items
    raise RuntimeError("catalog exceeded the 100,000-entry safety limit")


def parse_time(value):
    return dt.datetime.fromisoformat(value.replace("Z", "+00:00"))


def summarize(items):
    now = dt.datetime.now(dt.timezone.utc)
    methods = Counter(item.get("method") or "MISSING" for item in items)
    types = Counter(item.get("type") or "MISSING" for item in items)
    hosts = Counter()
    schemes = Counter()
    stale = Counter()

    for item in items:
        resource = item.get("resource") or ""
        parsed = urllib.parse.urlparse(resource)
        if parsed.scheme in {"http", "https"} and parsed.hostname:
            hosts[parsed.hostname] += 1
        else:
            schemes[parsed.scheme or "missing"] += 1

        updated = item.get("lastUpdated")
        if updated:
            age = now - parse_time(updated)
            for days in (1, 7, 30, 90, 180):
                if age >= dt.timedelta(days=days):
                    stale[f"at_least_{days}_days"] += 1

    return {
        "measured_at": now.isoformat().replace("+00:00", "Z"),
        "source": CATALOG,
        "method": "Catalog-only inventory; seller endpoints were not invoked.",
        "totals": {
            "entries": len(items),
            "unique_http_hosts": len(hosts),
            "entries_missing_method": methods["MISSING"],
            "non_http_resource_identifiers": sum(schemes.values()),
        },
        "methods": dict(methods.most_common()),
        "types": dict(types.most_common()),
        "non_http_schemes": dict(schemes.most_common()),
        "freshness": dict(stale),
        "largest_hosts": [{"host": host, "entries": count} for host, count in hosts.most_common(20)],
        "oldest_last_updated": min(item["lastUpdated"] for item in items if item.get("lastUpdated")),
        "newest_last_updated": max(item["lastUpdated"] for item in items if item.get("lastUpdated")),
    }


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--out", help="Write JSON here instead of stdout")
    args = parser.parse_args()
    result = json.dumps(summarize(fetch_all()), indent=2) + "\n"
    if args.out:
        with open(args.out, "w", encoding="utf-8") as handle:
            handle.write(result)
    else:
        print(result, end="")


if __name__ == "__main__":
    main()
