"""Check the interval statement of the worked state-at-date example, without trusting DEUSPROOF.

Reads interval-statement.json, ledger-interval.json and checkpoint-1672.json from this folder, plus two
public endpoints (the version-2 record and an inclusion proof). Needs Python 3.10+ and `cryptography`.
With --bitcoin it also checks the OpenTimestamps proof against the block header (needs `opentimestamps`
and network access to blockstream.info).

    python check_interval.py [--bitcoin]
"""

import base64
import hashlib
import json
import sys
import urllib.request
from pathlib import Path

AQUI = Path(__file__).resolve().parent
API = "https://deusproof.com/api"
B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"


def leer(nombre: str) -> dict:
    return json.loads((AQUI / nombre).read_text(encoding="utf-8"))


def traer(url: str) -> dict:
    req = urllib.request.Request(url, headers={"User-Agent": "state-at-date-example-check"})
    with urllib.request.urlopen(req, timeout=30) as r:
        return json.load(r)


def canonico(o: dict) -> bytes:
    return json.dumps(o, sort_keys=True, separators=(",", ":")).encode("utf-8")


def llave_did_key(did: str) -> bytes:
    n = 0
    texto = did.split("did:key:z", 1)[1]
    for c in texto:
        n = n * 58 + B58.index(c)
    crudo = n.to_bytes((n.bit_length() + 7) // 8, "big")
    crudo = b"\0" * (len(texto) - len(texto.lstrip("1"))) + crudo
    assert crudo[:2] == b"\xed\x01", "not an Ed25519 did:key"
    return crudo[2:]


def main() -> int:
    st, led, cp = leer("interval-statement.json"), leer("ledger-interval.json"), leer("checkpoint-1672.json")
    E = led["entries"]
    campos = ("prev_hash", "certification_id", "agent_did", "platform", "output_hash", "created_at")
    resultado = {}

    resultado["1_entries_rebuild_and_chain"] = all(
        hashlib.sha256(canonico({k: e[k] for k in campos})).hexdigest() == e["entry_hash"] for e in E
    ) and all(E[i]["prev_hash"] == E[i - 1]["entry_hash"] for i in range(1, len(E)))

    v2 = traer(f"{API}/verify/{st['interval']['from']['record'].rsplit('/', 1)[1]}")
    resultado["2_starts_at_version_2"] = v2["ledger_entry_hash"] == E[0]["entry_hash"] == st["interval"]["from"]["entryHash"]

    ultima = E[-1]
    inc = traer(f"{API}/anchors/inclusion/{ultima['certification_id']}")
    resultado["3_last_entry_in_checkpoint"] = (
        inc["checkpoint_id"] == cp["id"] and inc["merkle_root"] == cp["merkle_root"]
        and inc["entry_hash"] == ultima["entry_hash"] and inc["leaf_index"] == ultima["position"]
        and inc["tree_size"] == cp["tree_size"] and inc["verified"]
    )

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

    emisor = traer(f"{API}/anchors/issuer")
    try:
        Ed25519PublicKey.from_public_bytes(llave_did_key(cp["signer"])).verify(
            base64.b64decode(cp["signature_b64"]), cp["signed_payload"].encode("utf-8"))
        firma = True
    except Exception:
        firma = False
    resultado["4_operator_signature"] = firma and emisor.get("current_did") == cp["signer"] and bool(emisor.get("chain_valid"))

    eventos = [e["certification_id"] for e in E[1:] if e["agent_did"] == st["credentialIssuerOnLedger"]]
    resultado["6_no_event_for_credential"] = eventos == [] == st["eventsForCredential"]

    if "--bitcoin" in sys.argv:
        from opentimestamps.core.notary import BitcoinBlockHeaderAttestation
        from opentimestamps.core.serialize import BytesDeserializationContext
        from opentimestamps.core.timestamp import DetachedTimestampFile

        digest = hashlib.sha256(cp["signed_payload"].encode("utf-8")).digest()
        ots = DetachedTimestampFile.deserialize(BytesDeserializationContext(base64.b64decode(cp["ots_proof_b64"])))
        ts = ots.timestamp
        bueno = ts.msg == digest
        for msg, att in ts.all_attestations():
            if isinstance(att, BitcoinBlockHeaderAttestation) and att.height == cp["bitcoin_block"]:
                req = urllib.request.Request(f"https://blockstream.info/api/block-height/{att.height}")
                bloque = urllib.request.urlopen(req, timeout=30).read().decode()
                cab = traer(f"https://blockstream.info/api/block/{bloque}")
                bueno = bueno and msg[::-1].hex() == cab["merkle_root"]
        resultado["5_bitcoin_anchor"] = bueno

    print(json.dumps(resultado, indent=1))
    return 0 if all(resultado.values()) else 1


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