"""Tests for Ed25519 authentication."""
import base64
import json
import tempfile
from pathlib import Path

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

from botcoin.auth import BotcoinAuth


class TestBotcoinAuth:
    """Tests for BotcoinAuth class."""

    def test_generate_creates_valid_keypair(self):
        """Test that generate() produces valid Ed25519 keys."""
        private_hex, public_hex = BotcoinAuth.generate()

        # Should be 32 bytes each (64 hex chars)
        assert len(private_hex) == 64
        assert len(public_hex) == 64

        # Should be valid hex
        bytes.fromhex(private_hex)
        bytes.fromhex(public_hex)

    def test_generate_creates_unique_keys(self):
        """Test that each generate() call produces different keys."""
        key1 = BotcoinAuth.generate()
        key2 = BotcoinAuth.generate()

        assert key1[0] != key2[0]  # Different private keys
        assert key1[1] != key2[1]  # Different public keys

    def test_sign_produces_valid_signature(self):
        """Test that sign() produces verifiable signatures."""
        private_hex, public_hex = BotcoinAuth.generate()
        auth = BotcoinAuth("test-agent", private_hex, public_hex)

        body = '{"test": "data"}'
        signature_b64, timestamp = auth.sign(body)

        # Reconstruct message
        message = f"{timestamp}.{body}"

        # Verify signature
        signature = base64.b64decode(signature_b64)
        public_key = Ed25519PublicKey.from_public_bytes(bytes.fromhex(public_hex))
        # This will raise if invalid
        public_key.verify(signature, message.encode())

    def test_sign_different_bodies_different_signatures(self):
        """Test that different bodies produce different signatures."""
        private_hex, public_hex = BotcoinAuth.generate()
        auth = BotcoinAuth("test-agent", private_hex, public_hex)

        sig1, _ = auth.sign('{"a": 1}')
        sig2, _ = auth.sign('{"b": 2}')

        assert sig1 != sig2

    def test_headers_returns_correct_format(self):
        """Test that headers() returns properly formatted auth headers."""
        private_hex, public_hex = BotcoinAuth.generate()
        auth = BotcoinAuth("test-agent-123", private_hex, public_hex)

        body = '{"content": "test"}'
        headers = auth.headers(body)

        assert headers["Content-Type"] == "application/json"
        assert headers["X-Agent-Id"] == "test-agent-123"
        assert "X-Signature" in headers
        assert "X-Timestamp" in headers
        assert headers["X-Timestamp"].isdigit()

    def test_save_and_load_roundtrip(self):
        """Test saving and loading credentials."""
        private_hex, public_hex = BotcoinAuth.generate()
        auth = BotcoinAuth("test-agent-save", private_hex, public_hex)

        with tempfile.TemporaryDirectory() as tmpdir:
            path = Path(tmpdir) / "agent.json"
            auth.save(path, name="my-agent")

            # Load it back
            loaded = BotcoinAuth.load(path)

            assert loaded.agent_id == "test-agent-save"
            assert loaded.private_key_hex == private_hex
            assert loaded.public_key_hex == public_hex

            # Verify the file contents
            with open(path) as f:
                data = json.load(f)
            assert data["name"] == "my-agent"

    def test_derives_public_key_if_not_provided(self):
        """Test that public key is derived from private key if not provided."""
        private_hex, expected_public_hex = BotcoinAuth.generate()

        # Create auth without public key
        auth = BotcoinAuth("test-agent", private_hex, "")

        # Should derive the public key
        assert auth.public_key_hex == expected_public_hex
