"""
Coverage tests for primitives/schnorr.py - untested branches.
"""

from bsv.curve import curve, curve_add, curve_multiply
from bsv.keys import PrivateKey

# ========================================================================
# Schnorr Zero-Knowledge Proof branches
# ========================================================================


def test_schnorr_sign():
    """Test Schnorr proof generation (equivalent to signing)."""
    from bsv.primitives.schnorr import Schnorr

    schnorr = Schnorr()
    a = PrivateKey()
    b = PrivateKey()
    A = a.public_key()
    B = b.public_key()
    S = curve_multiply(a.int(), B.point())  # Shared secret

    proof = schnorr.generate_proof(a, A, B, S)

    assert isinstance(proof, dict)
    assert "R" in proof
    assert "SPrime" in proof
    assert "z" in proof
    assert isinstance(proof["z"], int)


def test_schnorr_verify_valid():
    """Test verifying valid Schnorr proof."""
    from bsv.primitives.schnorr import Schnorr

    schnorr = Schnorr()
    a = PrivateKey()
    b = PrivateKey()
    A = a.public_key()
    B = b.public_key()
    S = curve_multiply(a.int(), B.point())  # Shared secret

    proof = schnorr.generate_proof(a, A, B, S)
    is_valid = schnorr.verify_proof(A.point(), B.point(), S, proof)

    assert is_valid


def test_schnorr_verify_invalid():
    """Test verifying invalid Schnorr proof."""
    from bsv.primitives.schnorr import Schnorr

    schnorr = Schnorr()
    a = PrivateKey()
    b = PrivateKey()
    A = a.public_key()
    B = b.public_key()
    S = curve_multiply(a.int(), B.point())

    # Create invalid proof with tampered z
    proof = schnorr.generate_proof(a, A, B, S)
    invalid_proof = {**proof, "z": (proof["z"] + 1) % curve.n}

    is_valid = schnorr.verify_proof(A.point(), B.point(), S, invalid_proof)
    assert not is_valid


def test_schnorr_verify_wrong_key():
    """Test Schnorr verification with wrong public key."""
    from bsv.primitives.schnorr import Schnorr

    schnorr = Schnorr()
    a = PrivateKey()
    b = PrivateKey()
    wrong_b = PrivateKey()
    A = a.public_key()
    B = b.public_key()
    wrong_b_pub = wrong_b.public_key()
    S = curve_multiply(a.int(), B.point())

    proof = schnorr.generate_proof(a, A, B, S)
    # Verify with wrong public key B
    is_valid = schnorr.verify_proof(A.point(), wrong_b_pub.point(), S, proof)

    assert not is_valid


# ========================================================================
# Edge cases
# ========================================================================


def test_schnorr_sign_empty_message():
    """Test Schnorr proof generation with edge case inputs."""
    from bsv.primitives.schnorr import Schnorr

    schnorr = Schnorr()
    a = PrivateKey()
    b = PrivateKey()
    A = a.public_key()
    B = b.public_key()
    S = curve_multiply(a.int(), B.point())

    # Generate proof - should work with valid inputs
    proof = schnorr.generate_proof(a, A, B, S)
    assert proof is not None
    assert isinstance(proof, dict)


def test_schnorr_sign_wrong_message_size():
    """Test Schnorr proof generation with incorrect shared secret fails verification."""
    from bsv.primitives.schnorr import Schnorr

    schnorr = Schnorr()
    a = PrivateKey()
    b = PrivateKey()
    A = a.public_key()
    B = b.public_key()

    # Correct shared secret: S = a * B
    correct_s = curve_multiply(a.int(), B.point())

    # Generate proof with correct shared secret
    proof = schnorr.generate_proof(a, A, B, correct_s)

    # This should verify correctly
    is_valid_correct = schnorr.verify_proof(A.point(), B.point(), correct_s, proof)
    assert is_valid_correct

    # Create incorrect shared secret by adding generator point (breaks the relationship)
    incorrect_s = curve_add(correct_s, curve.g) if correct_s else curve.g

    # Verify proof with incorrect shared secret (should fail)
    is_valid_wrong = schnorr.verify_proof(A.point(), B.point(), incorrect_s, proof)
    assert not is_valid_wrong


def test_schnorr_deterministic():
    """Test Schnorr proofs are deterministic with same inputs."""
    from bsv.primitives.schnorr import Schnorr

    schnorr = Schnorr()
    # Use fixed private keys for determinism
    a_int = int("123456789abcdef123456789abcdef123456789abcdef123456789abcdef", 16)
    b_int = int("abcdef123456789abcdef123456789abcdef123456789abcdef123456789", 16)
    a = PrivateKey(a_int)
    b = PrivateKey(b_int)
    A = a.public_key()
    B = b.public_key()
    S = curve_multiply(a.int(), B.point())

    # Note: Schnorr ZKP uses random r, so proofs won't be deterministic
    # But we can test that the same inputs produce valid proofs
    proof1 = schnorr.generate_proof(a, A, B, S)
    proof2 = schnorr.generate_proof(a, A, B, S)

    # Both proofs should verify
    assert schnorr.verify_proof(A.point(), B.point(), S, proof1)
    assert schnorr.verify_proof(A.point(), B.point(), S, proof2)

    # Proofs may differ due to random r, but both should be valid
    assert isinstance(proof1["z"], int)
    assert isinstance(proof2["z"], int)
