"""NEOva wire primitives for the anchoring adapter (§2.5 seam, guardrail #4).

Byte-exact reimplementation of the OpaqueCommitmentEnvelope encoding defined by
NEOTRUST↔NEOVA SEAM v0.6 (LOCKED) and pinned by its golden vectors. This lives
entirely in cotrugli-ledger — the adapter speaks the substrate's wire format,
exactly as `neo_admission.py` reimplements NEO's fixint-bincode admission;
nothing ABOVE the adapter ever sees these details (substrate never leaks up).

Divergence is self-announcing: a wrong digest here fails engine admission as
REJECT_BAD_SIG in the live e2e (tools/live_neova_anchor_e2e.py), and the unit
suite pins a golden envelope digest computed by the engine implementation.
"""

from __future__ import annotations

import hashlib
import json

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

ENVELOPE_DOMAIN = "NEOVA:ENVELOPE:V1"

#: seam §2 required fields (everything except gateway_signature is signed)
REQUIRED_FIELDS = ("protocol_id", "network_id", "envelope_version",
                   "object_root", "scope_key", "namespace_id", "gateway_id",
                   "gateway_epoch", "gateway_sequence")


def canonical(obj) -> bytes:
    """Seam canonical JSON: sorted keys, tight separators, raw UTF-8."""
    return json.dumps(obj, sort_keys=True, separators=(",", ":"),
                      ensure_ascii=False).encode()


def H(domain: str, *parts) -> bytes:
    """Seam domain-separated hash: sha256(domain ‖ 0x00 ‖ Σ(len4be ‖ part))."""
    h = hashlib.sha256()
    h.update(domain.encode() + b"\x00")
    for p in parts:
        b = p if isinstance(p, bytes) else canonical(p)
        h.update(len(b).to_bytes(4, "big") + b)
    return h.digest()


def envelope_payload(env: dict) -> dict:
    """The signed view: every field except the signature, bytes hex-encoded."""
    return {k: (v.hex() if isinstance(v, bytes) else v) for k, v in env.items()
            if k != "gateway_signature"}


def envelope_digest(env: dict) -> bytes:
    return H(ENVELOPE_DOMAIN, envelope_payload(env))


def build_wire_envelope(network_id: str, object_root: bytes, scope_key: bytes,
                        namespace_id: str, gateway_id: str, gateway_epoch: int,
                        gateway_sequence: int,
                        gateway_sk: Ed25519PrivateKey) -> dict:
    """Build a signed envelope and return it in WIRE encoding (the three bytes
    fields hex-encoded), ready for POST /v2/submit {"envelopes": [...]}."""
    if len(object_root) != 32 or len(scope_key) != 32:
        raise ValueError("object_root and scope_key must be 32 bytes")
    env = {"protocol_id": "NEOVA", "network_id": network_id,
           "envelope_version": 1, "object_root": object_root,
           "scope_key": scope_key, "namespace_id": namespace_id,
           "gateway_id": gateway_id, "gateway_epoch": gateway_epoch,
           "gateway_sequence": gateway_sequence}
    sig = gateway_sk.sign(envelope_digest(env))
    return {"protocol_id": env["protocol_id"], "network_id": network_id,
            "envelope_version": 1, "object_root": object_root.hex(),
            "scope_key": scope_key.hex(), "namespace_id": namespace_id,
            "gateway_id": gateway_id, "gateway_epoch": gateway_epoch,
            "gateway_sequence": gateway_sequence,
            "gateway_signature": sig.hex()}
