"""Tests for act.crypto module."""

import pytest

from act.crypto import (
    ACTKeyResolver,
    KeyRegistry,
    X509TrustStore,
    b64url_sha256,
    compute_sha256,
    did_key_from_ed25519,
    generate_ed25519_keypair,
    generate_p256_keypair,
    resolve_did_key,
    sign,
    verify,
)
from act.errors import ACTKeyResolutionError, ACTSignatureError


class TestEd25519:
    def test_generate_keypair(self):
        priv, pub = generate_ed25519_keypair()
        assert priv is not None
        assert pub is not None

    def test_sign_verify(self):
        priv, pub = generate_ed25519_keypair()
        data = b"test data"
        sig = sign(priv, data)
        verify(pub, sig, data)

    def test_verify_wrong_data(self):
        priv, pub = generate_ed25519_keypair()
        sig = sign(priv, b"correct data")
        with pytest.raises(ACTSignatureError):
            verify(pub, sig, b"wrong data")

    def test_verify_wrong_key(self):
        priv1, pub1 = generate_ed25519_keypair()
        _, pub2 = generate_ed25519_keypair()
        sig = sign(priv1, b"data")
        with pytest.raises(ACTSignatureError):
            verify(pub2, sig, b"data")


class TestP256:
    def test_generate_keypair(self):
        priv, pub = generate_p256_keypair()
        assert priv is not None
        assert pub is not None

    def test_sign_verify(self):
        priv, pub = generate_p256_keypair()
        data = b"test data for p256"
        sig = sign(priv, data)
        assert len(sig) == 64  # r||s, 32 bytes each
        verify(pub, sig, data)

    def test_verify_wrong_data(self):
        priv, pub = generate_p256_keypair()
        sig = sign(priv, b"correct")
        with pytest.raises(ACTSignatureError):
            verify(pub, sig, b"wrong")


class TestSHA256:
    def test_compute(self):
        h = compute_sha256(b"hello")
        assert len(h) == 32

    def test_b64url(self):
        result = b64url_sha256(b"hello world")
        assert "=" not in result
        assert isinstance(result, str)


class TestKeyRegistry:
    def test_register_and_get(self):
        reg = KeyRegistry()
        _, pub = generate_ed25519_keypair()
        reg.register("key-1", pub)
        assert reg.get("key-1") is pub
        assert "key-1" in reg
        assert len(reg) == 1

    def test_missing_key(self):
        reg = KeyRegistry()
        assert reg.get("missing") is None
        assert "missing" not in reg


class TestDIDKey:
    def test_ed25519_roundtrip(self):
        _, pub = generate_ed25519_keypair()
        did = did_key_from_ed25519(pub)
        assert did.startswith("did:key:z6Mk")
        resolved = resolve_did_key(did)
        # Verify same key by signing/verifying
        from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
        original_bytes = pub.public_bytes(Encoding.Raw, PublicFormat.Raw)
        resolved_bytes = resolved.public_bytes(Encoding.Raw, PublicFormat.Raw)
        assert original_bytes == resolved_bytes

    def test_invalid_prefix(self):
        with pytest.raises(ACTKeyResolutionError):
            resolve_did_key("did:web:example.com")

    def test_with_fragment(self):
        _, pub = generate_ed25519_keypair()
        did = did_key_from_ed25519(pub)
        did_with_fragment = f"{did}#{did.split(':')[2]}"
        resolved = resolve_did_key(did_with_fragment)
        assert resolved is not None


class TestACTKeyResolver:
    def test_tier1_resolution(self):
        reg = KeyRegistry()
        _, pub = generate_ed25519_keypair()
        reg.register("my-key", pub)
        resolver = ACTKeyResolver(registry=reg)
        assert resolver.resolve("my-key") is pub

    def test_tier3_did_key(self):
        _, pub = generate_ed25519_keypair()
        did = did_key_from_ed25519(pub)
        resolver = ACTKeyResolver()
        resolved = resolver.resolve(did)
        assert resolved is not None

    def test_unresolvable(self):
        resolver = ACTKeyResolver()
        with pytest.raises(ACTKeyResolutionError):
            resolver.resolve("unknown-kid")

    def test_did_web_resolver_callback(self):
        _, pub = generate_ed25519_keypair()
        def resolver_cb(did: str):
            if did == "did:web:example.com":
                return pub
            return None
        resolver = ACTKeyResolver(did_web_resolver=resolver_cb)
        result = resolver.resolve("did:web:example.com")
        assert result is pub
