"""Tests for the DeviceResponse builder used in the step-up phase."""

import cbor2
import pytest
from cryptography.hazmat.primitives.asymmetric import ec

from aliro_harness.issuer.access_document import build_access_document
from aliro_harness.issuer.cose import verify_cose_sign1
from aliro_harness.issuer.device_response import build_device_response


@pytest.fixture
def issuer_key():
    return ec.generate_private_key(ec.SECP256R1())


@pytest.fixture
def access_doc(issuer_key):
    return build_access_document(
        issuer_private_key=issuer_key,
        access_credential_public_key=ec.generate_private_key(ec.SECP256R1()).public_key(),
    )


def test_device_response_has_aliro_remapped_top_level_keys(access_doc):
    decoded = cbor2.loads(build_device_response(access_doc))
    assert set(decoded.keys()) == {"1", "2", "3"}, (
        "top-level keys must be Aliro Table 8-22 aliases (version, documents, status)"
    )


def test_device_response_version_is_1_0(access_doc):
    decoded = cbor2.loads(build_device_response(access_doc))
    assert decoded["1"] == "1.0"


def test_device_response_status_is_ok(access_doc):
    decoded = cbor2.loads(build_device_response(access_doc))
    assert decoded["3"] == 0


def test_device_response_has_exactly_one_document(access_doc):
    decoded = cbor2.loads(build_device_response(access_doc))
    assert isinstance(decoded["2"], list)
    assert len(decoded["2"]) == 1


def test_document_doctype_is_aliro_a(access_doc):
    decoded = cbor2.loads(build_device_response(access_doc))
    assert decoded["2"][0]["5"] == "aliro-a"


def test_issuer_signed_has_empty_namespaces(access_doc):
    decoded = cbor2.loads(build_device_response(access_doc))
    issuer_signed = decoded["2"][0]["1"]
    assert issuer_signed["1"] == {}, "v1 returns no Access Data Elements"


def test_issuer_auth_is_the_original_cose_sign1(access_doc, issuer_key):
    """IssuerAuth embedded in DeviceResponse must still verify as a valid
    COSE_Sign1 under the issuer's public key — i.e. the AD bytes round-trip."""
    decoded = cbor2.loads(build_device_response(access_doc))
    issuer_auth = decoded["2"][0]["1"]["2"]
    assert isinstance(issuer_auth, list) and len(issuer_auth) == 4, (
        "IssuerAuth is a 4-element COSE_Sign1 array"
    )
    # Re-serialize and verify.
    reserialized = cbor2.dumps(issuer_auth, canonical=True)
    payload = verify_cose_sign1(reserialized, issuer_key.public_key())
    assert isinstance(payload, bytes) and len(payload) > 0


def test_forbidden_fields_absent(access_doc):
    """Per Aliro §8.4.2, documentErrors / errors / deviceSigned / readerAuth
    SHALL NOT be present."""
    decoded = cbor2.loads(build_device_response(access_doc))
    doc = decoded["2"][0]
    assert "documentErrors" not in decoded
    assert "errors" not in decoded
    assert "documentErrors" not in doc
    assert "errors" not in doc
    assert "deviceSigned" not in doc


def test_device_response_is_deterministic(access_doc):
    """Same inputs must produce byte-identical CBOR."""
    a = build_device_response(access_doc)
    b = build_device_response(access_doc)
    assert a == b, "DeviceResponse must be deterministic CBOR for a given AD"


def test_device_response_fits_within_realistic_apdu_budget(access_doc):
    """Sanity-check that encrypted response size stays under the step-up
    APDU chain budget (ENVELOPE/GET RESPONSE supports >2000 bytes with
    extended-length support, but we want to stay comfortably small)."""
    encoded = build_device_response(access_doc)
    assert len(encoded) < 2000, f"DeviceResponse is {len(encoded)} bytes"
