#!/usr/bin/env python3
"""Standalone verifier for AttributionResult ed25519 signatures.

stdlib + `cryptography` only — NO fifty50 imports. Recomputes canonical_result_bytes/v1 identically
to fifty50/core/attribution_signing.py so a customer can verify a signed equity split offline,
against the embedded public key, without trusting our database.

    python verify_attribution_signature.py signed_result.json    # or pipe JSON on stdin

Prints VALID / INVALID, exits 0 / 1.
"""
from __future__ import annotations

import json
import sys
from datetime import datetime, timezone

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey


def _as_utc(dt):
    return dt.replace(tzinfo=timezone.utc) if dt.tzinfo is None else dt.astimezone(timezone.utc)


def canonical_occurred_at(value):
    if isinstance(value, datetime):
        dt = value
    elif isinstance(value, str):
        s = value.strip()
        s = s[:-1] + "+00:00" if s.endswith("Z") else s
        dt = datetime.fromisoformat(s)
    else:
        raise TypeError("generated_at must be datetime or ISO str")
    dt = _as_utc(dt)
    return dt.strftime("%Y-%m-%dT%H:%M:%S.") + f"{dt.microsecond:06d}Z"


def _get(obj, key, default):
    return obj.get(key, default) if isinstance(obj, dict) else getattr(obj, key, default)


def _partners_for_canonical(result) -> list:
    out = []
    for p in list(_get(result, "partners", []) or []):
        out.append({
            "partner_id": _get(p, "partner_id", None),
            "equity_share": "%.12f" % float(_get(p, "equity_share", 0)),
        })
    out.sort(key=lambda x: x["partner_id"] or "")
    return out


def to_canonical_dict(result) -> dict:
    return {
        "generated_at": canonical_occurred_at(_get(result, "generated_at", None)),
        "model_version_id": _get(result, "model_version_id", None),
        "partnership_id": _get(result, "partnership_id", None),
        "partners": _partners_for_canonical(result),
    }


def canonical_result_bytes(result) -> bytes:
    return json.dumps(to_canonical_dict(result), sort_keys=True, separators=(",", ":")).encode("utf-8")


def verify_signed_json(data: dict) -> bool:
    try:
        if data.get("algo") != "ed25519" or data.get("signed_over") != "canonical_result_bytes/v1":
            return False
        sig_hex = data.get("signature")
        pub_hex = data.get("public_key")
        if not sig_hex or not pub_hex:
            return False
        result = {
            "partnership_id": data.get("partnership_id"),
            "model_version_id": data.get("model_version_id"),
            "generated_at": data.get("generated_at"),
            "partners": data.get("partners", []) or [],
        }
        public_key = Ed25519PublicKey.from_public_bytes(bytes.fromhex(pub_hex))
        public_key.verify(bytes.fromhex(sig_hex), canonical_result_bytes(result))
        return True
    except Exception:
        return False


def main(argv=None) -> int:
    argv = list(sys.argv[1:] if argv is None else argv)
    try:
        with open(argv[0], "r", encoding="utf-8") as f:
            data = json.load(f)
    except IndexError:
        data = json.load(sys.stdin)
    except Exception:
        print("INVALID")
        return 1
    if verify_signed_json(data):
        print("VALID")
        return 0
    print("INVALID")
    return 1


if __name__ == "__main__":
    sys.exit(main())
