"""Tests for JWS signing functionality."""

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from cryptography.hazmat.primitives.asymmetric.ec import (
        EllipticCurvePrivateKey,
        EllipticCurvePublicKey,
    )
    from cryptography.hazmat.primitives.asymmetric.ed25519 import (
        Ed25519PrivateKey,
        Ed25519PublicKey,
    )

from mailio_receipt.signing import create_jws_detached, verify_jws_detached


class TestCreateJwsDetached:
    """Tests for create_jws_detached function."""

    def test_creates_valid_jws(self, agent_private_key: EllipticCurvePrivateKey) -> None:
        """Test that create_jws_detached creates a valid JWS."""
        payload = b'{"hello":"world"}'
        key_id = "key-1"

        jws = create_jws_detached(payload, agent_private_key, key_id)

        # JWS compact format: header..signature (no payload for detached)
        parts = jws.split(".")
        assert len(parts) == 3
        # Middle part (payload) should be empty for detached JWS
        assert parts[1] == ""

    def test_jws_header_contains_alg(self, agent_private_key: EllipticCurvePrivateKey) -> None:
        """Test that JWS header contains algorithm."""
        import base64
        import json

        payload = b'{"hello":"world"}'
        key_id = "key-1"

        jws = create_jws_detached(payload, agent_private_key, key_id)
        header_b64 = jws.split(".")[0]

        # Add padding if needed
        padding = 4 - len(header_b64) % 4
        if padding != 4:
            header_b64 += "=" * padding

        header = json.loads(base64.urlsafe_b64decode(header_b64))
        assert header["alg"] == "ES256"

    def test_jws_header_contains_alg_ed25519(
        self, ed25519_agent_private_key: Ed25519PrivateKey
    ) -> None:
        """Test that JWS header contains EdDSA for Ed25519 keys."""
        import base64
        import json

        payload = b'{"hello":"world"}'
        key_id = "key-1"

        jws = create_jws_detached(payload, ed25519_agent_private_key, key_id)
        header_b64 = jws.split(".")[0]

        # Add padding if needed
        padding = 4 - len(header_b64) % 4
        if padding != 4:
            header_b64 += "=" * padding

        header = json.loads(base64.urlsafe_b64decode(header_b64))
        assert header["alg"] == "EdDSA"

    def test_jws_header_contains_kid(self, agent_private_key: EllipticCurvePrivateKey) -> None:
        """Test that JWS header contains key ID."""
        import base64
        import json

        payload = b'{"hello":"world"}'
        key_id = "my-key-id"

        jws = create_jws_detached(payload, agent_private_key, key_id)
        header_b64 = jws.split(".")[0]

        # Add padding if needed
        padding = 4 - len(header_b64) % 4
        if padding != 4:
            header_b64 += "=" * padding

        header = json.loads(base64.urlsafe_b64decode(header_b64))
        assert header["kid"] == "my-key-id"

    def test_different_payloads_different_signatures(
        self, agent_private_key: EllipticCurvePrivateKey
    ) -> None:
        """Test that different payloads produce different signatures."""
        payload1 = b'{"data":"one"}'
        payload2 = b'{"data":"two"}'
        key_id = "key-1"

        jws1 = create_jws_detached(payload1, agent_private_key, key_id)
        jws2 = create_jws_detached(payload2, agent_private_key, key_id)

        # Signatures should be different
        sig1 = jws1.split(".")[2]
        sig2 = jws2.split(".")[2]
        assert sig1 != sig2


class TestVerifyJwsDetached:
    """Tests for verify_jws_detached function."""

    def test_verify_valid_signature(
        self,
        agent_private_key: EllipticCurvePrivateKey,
        agent_public_key: EllipticCurvePublicKey,
    ) -> None:
        """Test that valid signature verifies successfully."""
        payload = b'{"hello":"world"}'
        key_id = "key-1"

        jws = create_jws_detached(payload, agent_private_key, key_id)
        result = verify_jws_detached(jws, payload, agent_public_key)

        assert result is True

    def test_verify_fails_with_wrong_payload(
        self,
        agent_private_key: EllipticCurvePrivateKey,
        agent_public_key: EllipticCurvePublicKey,
    ) -> None:
        """Test that verification fails with wrong payload."""
        original_payload = b'{"hello":"world"}'
        wrong_payload = b'{"hello":"modified"}'
        key_id = "key-1"

        jws = create_jws_detached(original_payload, agent_private_key, key_id)
        result = verify_jws_detached(jws, wrong_payload, agent_public_key)

        assert result is False

    def test_verify_fails_with_wrong_key(
        self,
        agent_private_key: EllipticCurvePrivateKey,
        user_public_key: EllipticCurvePublicKey,
    ) -> None:
        """Test that verification fails with wrong public key."""
        payload = b'{"hello":"world"}'
        key_id = "key-1"

        jws = create_jws_detached(payload, agent_private_key, key_id)
        result = verify_jws_detached(jws, payload, user_public_key)

        assert result is False

    def test_verify_fails_with_tampered_signature(
        self,
        agent_private_key: EllipticCurvePrivateKey,
        agent_public_key: EllipticCurvePublicKey,
    ) -> None:
        """Test that verification fails with tampered signature."""
        payload = b'{"hello":"world"}'
        key_id = "key-1"

        jws = create_jws_detached(payload, agent_private_key, key_id)

        # Tamper with the signature
        parts = jws.split(".")
        tampered_sig = "A" + parts[2][1:] if parts[2][0] != "A" else "B" + parts[2][1:]
        tampered_jws = f"{parts[0]}..{tampered_sig}"

        result = verify_jws_detached(tampered_jws, payload, agent_public_key)

        assert result is False

    def test_verify_valid_signature_ed25519(
        self,
        ed25519_agent_private_key: Ed25519PrivateKey,
        ed25519_agent_public_key: Ed25519PublicKey,
    ) -> None:
        """Test that Ed25519 signatures verify successfully."""
        payload = b'{"hello":"world"}'
        key_id = "key-1"

        jws = create_jws_detached(payload, ed25519_agent_private_key, key_id)
        result = verify_jws_detached(jws, payload, ed25519_agent_public_key)

        assert result is True

    def test_verify_fails_with_wrong_payload_ed25519(
        self,
        ed25519_agent_private_key: Ed25519PrivateKey,
        ed25519_agent_public_key: Ed25519PublicKey,
    ) -> None:
        """Test that Ed25519 verification fails with wrong payload."""
        original_payload = b'{"hello":"world"}'
        wrong_payload = b'{"hello":"modified"}'
        key_id = "key-1"

        jws = create_jws_detached(original_payload, ed25519_agent_private_key, key_id)
        result = verify_jws_detached(jws, wrong_payload, ed25519_agent_public_key)

        assert result is False

    def test_verify_fails_with_wrong_key_ed25519(
        self,
        ed25519_agent_private_key: Ed25519PrivateKey,
        ed25519_agent_public_key: Ed25519PublicKey,
    ) -> None:
        """Test that Ed25519 verification fails with wrong public key."""
        from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

        payload = b'{"hello":"world"}'
        key_id = "key-1"

        jws = create_jws_detached(payload, ed25519_agent_private_key, key_id)
        wrong_public_key = Ed25519PrivateKey.generate().public_key()
        result = verify_jws_detached(jws, payload, wrong_public_key)

        assert result is False
