"""Cross-language interoperability tests.

Verifies that Python-generated signatures follow the same format as the
TypeScript implementation, ensuring cross-language compatibility.
"""
import base64

from ucm.crypto import (
    canonical_json,
    generate_keypair,
    sha256_hex,
    sign_message,
    verify_message,
)


def test_signing_flow_matches_typescript():
    """
    Verify the full signing flow matches TypeScript:
    1. Build canonical JSON payload
    2. sha256Hex the payload
    3. UTF-8 encode the hex string
    4. Ed25519 sign those bytes
    5. base64url encode the signature
    """
    priv, pub = generate_keypair()

    # Simulate the exact flow from TypeScript verify-onboarding.ts
    body = '{"service_id":"demo/web-search","plan":"per-call"}'
    body_hash = sha256_hex(body)
    nonce = 'test-nonce-123'
    timestamp = 1700000000000

    payload = canonical_json({
        'body_hash': body_hash,
        'method': 'POST',
        'nonce': nonce,
        'path': '/v1/buy',
        'timestamp': timestamp,
    })

    # This is what TypeScript does: sign(sha256Hex(payload), privateKey)
    hash_str = sha256_hex(payload)
    signature = sign_message(priv, hash_str)

    # Verify signature format
    assert isinstance(signature, str)
    assert '=' not in signature  # no padding
    assert '+' not in signature  # base64url, not base64
    assert '/' not in signature  # base64url, not base64

    # Decode and verify it's 64 bytes (Ed25519 signature size)
    padded = signature + '=' * (-len(signature) % 4)
    sig_bytes = base64.urlsafe_b64decode(padded)
    assert len(sig_bytes) == 64

    # Verify with public key
    assert verify_message(pub, hash_str, signature) is True


def test_message_is_utf8_encoded_hex():
    """
    The signed message is a hex string (64 chars) that gets UTF-8 encoded.
    This means ed25519 signs 64 bytes (the UTF-8 encoding of 64 hex chars),
    NOT 32 bytes (the raw hash bytes).
    """
    priv, pub = generate_keypair()
    data = '{"test":"data"}'
    hex_hash = sha256_hex(data)

    # hex_hash is 64 hex chars
    assert len(hex_hash) == 64

    # When UTF-8 encoded, it's 64 bytes (one byte per ASCII hex char)
    assert len(hex_hash.encode('utf-8')) == 64

    # Sign and verify using the hex string as message
    sig = sign_message(priv, hex_hash)
    assert verify_message(pub, hex_hash, sig) is True

    # Signing the raw bytes (32 bytes) would produce a different signature
    # This is the bug that was fixed - the old code did bytes.fromhex(hash)
    # which gives 32 bytes instead of 64 bytes


def test_canonical_json_deterministic():
    """Canonical JSON must produce identical output regardless of key order."""
    obj1 = {'body_hash': 'abc', 'method': 'POST', 'nonce': 'n1', 'path': '/v1/buy', 'timestamp': 123}
    obj2 = {'timestamp': 123, 'path': '/v1/buy', 'nonce': 'n1', 'method': 'POST', 'body_hash': 'abc'}

    assert canonical_json(obj1) == canonical_json(obj2)


def test_roundtrip_with_known_message():
    """Sign a known message and verify the roundtrip works."""
    priv, pub = generate_keypair()

    # This is the exact format used in the protocol
    known_payload = canonical_json({
        'body_hash': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
        'method': 'GET',
        'nonce': '550e8400-e29b-41d4-a716-446655440000',
        'path': '/v1/balance',
        'timestamp': 1700000000000,
    })

    hash_str = sha256_hex(known_payload)
    sig = sign_message(priv, hash_str)

    # Verify succeeds
    assert verify_message(pub, hash_str, sig) is True

    # Verify fails with tampered hash
    tampered = 'a' + hash_str[1:]
    assert verify_message(pub, tampered, sig) is False
