package p256k1

import (
	"testing"
)

// TestSecp256k1SchnorrsigVerifyComparison tests that secp256k1_schnorrsig_verify
// produces the same results as the existing SchnorrVerify function
func TestSecp256k1SchnorrsigVerifyComparison(t *testing.T) {
	// Create a context (required by secp256k1_schnorrsig_verify)
	ctx := &secp256k1_context{
		ecmult_gen_ctx: secp256k1_ecmult_gen_context{built: 1},
		declassify:     0,
	}

	// Test case 1: Valid signature
	t.Run("ValidSignature", func(t *testing.T) {
		// Generate keypair
		kp, err := KeyPairGenerate()
		if err != nil {
			t.Fatalf("failed to generate keypair: %v", err)
		}
		defer kp.Clear()

		// Get x-only pubkey
		xonly, err := kp.XOnlyPubkey()
		if err != nil {
			t.Fatalf("failed to get x-only pubkey: %v", err)
		}

		// Create message
		msg := make([]byte, 32)
		for i := range msg {
			msg[i] = byte(i)
		}

		// Sign
		var sig [64]byte
		if err := SchnorrSign(sig[:], msg, kp, nil); err != nil {
			t.Fatalf("failed to sign: %v", err)
		}

		// Convert x-only pubkey to secp256k1_xonly_pubkey format
		var secp_xonly secp256k1_xonly_pubkey
		copy(secp_xonly.data[:], xonly.data[:])

		// Test existing implementation (old)
		existingResult := SchnorrVerifyOld(sig[:], msg, xonly)

		// Test new implementation (C-translated)
		newResult := SchnorrVerify(sig[:], msg, xonly)

		// Compare results
		if existingResult != newResult {
			t.Errorf("results differ: existing=%v, new=%v", existingResult, newResult)
		}

		if !existingResult {
			t.Error("signature verification failed (both implementations)")
		}
	})

	// Test case 2: Invalid signature (wrong message)
	t.Run("InvalidSignature_WrongMessage", func(t *testing.T) {
		// Generate keypair
		kp, err := KeyPairGenerate()
		if err != nil {
			t.Fatalf("failed to generate keypair: %v", err)
		}
		defer kp.Clear()

		// Get x-only pubkey
		xonly, err := kp.XOnlyPubkey()
		if err != nil {
			t.Fatalf("failed to get x-only pubkey: %v", err)
		}

		// Create message
		msg := make([]byte, 32)
		for i := range msg {
			msg[i] = byte(i)
		}

		// Sign
		var sig [64]byte
		if err := SchnorrSign(sig[:], msg, kp, nil); err != nil {
			t.Fatalf("failed to sign: %v", err)
		}

		// Create wrong message
		wrongMsg := make([]byte, 32)
		copy(wrongMsg, msg)
		wrongMsg[0] ^= 1

		// Convert x-only pubkey to secp256k1_xonly_pubkey format
		var secp_xonly secp256k1_xonly_pubkey
		copy(secp_xonly.data[:], xonly.data[:])

		// Test existing implementation (old)
		existingResult := SchnorrVerifyOld(sig[:], wrongMsg, xonly)

		// Test new implementation (C-translated)
		newResult := SchnorrVerify(sig[:], wrongMsg, xonly)

		// Compare results
		if existingResult != newResult {
			t.Errorf("results differ: existing=%v, new=%v", existingResult, newResult)
		}

		if existingResult {
			t.Error("signature verification should fail with wrong message (both implementations)")
		}
	})

	// Test case 3: Invalid signature (wrong signature)
	t.Run("InvalidSignature_WrongSignature", func(t *testing.T) {
		// Generate keypair
		kp, err := KeyPairGenerate()
		if err != nil {
			t.Fatalf("failed to generate keypair: %v", err)
		}
		defer kp.Clear()

		// Get x-only pubkey
		xonly, err := kp.XOnlyPubkey()
		if err != nil {
			t.Fatalf("failed to get x-only pubkey: %v", err)
		}

		// Create message
		msg := make([]byte, 32)
		for i := range msg {
			msg[i] = byte(i)
		}

		// Sign
		var sig [64]byte
		if err := SchnorrSign(sig[:], msg, kp, nil); err != nil {
			t.Fatalf("failed to sign: %v", err)
		}

		// Create wrong signature
		wrongSig := make([]byte, 64)
		copy(wrongSig, sig[:])
		wrongSig[0] ^= 1

		// Convert x-only pubkey to secp256k1_xonly_pubkey format
		var secp_xonly secp256k1_xonly_pubkey
		copy(secp_xonly.data[:], xonly.data[:])

		// Test existing implementation (old)
		existingResult := SchnorrVerifyOld(wrongSig, msg, xonly)

		// Test new implementation (C-translated)
		newResult := SchnorrVerify(wrongSig, msg, xonly)

		// Compare results
		if existingResult != newResult {
			t.Errorf("results differ: existing=%v, new=%v", existingResult, newResult)
		}

		if existingResult {
			t.Error("signature verification should fail with wrong signature (both implementations)")
		}
	})

	// Test case 4: Invalid signature (wrong pubkey)
	t.Run("InvalidSignature_WrongPubkey", func(t *testing.T) {
		// Generate two keypairs
		kp1, err := KeyPairGenerate()
		if err != nil {
			t.Fatalf("failed to generate keypair 1: %v", err)
		}
		defer kp1.Clear()

		kp2, err := KeyPairGenerate()
		if err != nil {
			t.Fatalf("failed to generate keypair 2: %v", err)
		}
		defer kp2.Clear()

		// Get x-only pubkey for kp2 (we sign with kp1, verify with kp2)
		xonly2, err := kp2.XOnlyPubkey()
		if err != nil {
			t.Fatalf("failed to get x-only pubkey 2: %v", err)
		}

		// Create message
		msg := make([]byte, 32)
		for i := range msg {
			msg[i] = byte(i)
		}

		// Sign with keypair 1
		var sig [64]byte
		if err := SchnorrSign(sig[:], msg, kp1, nil); err != nil {
			t.Fatalf("failed to sign: %v", err)
		}

		// Convert x-only pubkey 2 to secp256k1_xonly_pubkey format
		var secp_xonly2 secp256k1_xonly_pubkey
		copy(secp_xonly2.data[:], xonly2.data[:])

		// Test existing implementation (old, verify with wrong pubkey)
		existingResult := SchnorrVerifyOld(sig[:], msg, xonly2)

		// Test new implementation (C-translated, verify with wrong pubkey)
		newResult := SchnorrVerify(sig[:], msg, xonly2)

		// Compare results
		if existingResult != newResult {
			t.Errorf("results differ: existing=%v, new=%v", existingResult, newResult)
		}

		if existingResult {
			t.Error("signature verification should fail with wrong pubkey (both implementations)")
		}
	})

	// Test case 5: Edge cases - nil/invalid inputs
	t.Run("EdgeCases", func(t *testing.T) {
		// Generate keypair
		kp, err := KeyPairGenerate()
		if err != nil {
			t.Fatalf("failed to generate keypair: %v", err)
		}
		defer kp.Clear()

		// Get x-only pubkey
		xonly, err := kp.XOnlyPubkey()
		if err != nil {
			t.Fatalf("failed to get x-only pubkey: %v", err)
		}

		msg := make([]byte, 32)
		var sig [64]byte

		// Test with nil context
		var secp_xonly secp256k1_xonly_pubkey
		copy(secp_xonly.data[:], xonly.data[:])

		newResult := secp256k1_schnorrsig_verify(nil, sig[:], msg, len(msg), &secp_xonly)
		if newResult != 0 {
			t.Error("should return 0 with nil context")
		}

		// Test with nil signature
		newResult = secp256k1_schnorrsig_verify(ctx, nil, msg, len(msg), &secp_xonly)
		if newResult != 0 {
			t.Error("should return 0 with nil signature")
		}

		// Test with nil pubkey
		newResult = secp256k1_schnorrsig_verify(ctx, sig[:], msg, len(msg), nil)
		if newResult != 0 {
			t.Error("should return 0 with nil pubkey")
		}

		// Test with invalid signature length
		if SchnorrVerify([]byte{1}, msg, xonly) {
			t.Error("existing: should fail with invalid signature length")
		}
		newResult = secp256k1_schnorrsig_verify(ctx, []byte{1}, msg, len(msg), &secp_xonly)
		if newResult != 0 {
			t.Error("new: should return 0 with invalid signature length")
		}
	})

	// Test case 6: Multiple signatures with different aux_rand
	t.Run("MultipleSignatures_DifferentAuxRand", func(t *testing.T) {
		// Generate keypair
		kp, err := KeyPairGenerate()
		if err != nil {
			t.Fatalf("failed to generate keypair: %v", err)
		}
		defer kp.Clear()

		// Get x-only pubkey
		xonly, err := kp.XOnlyPubkey()
		if err != nil {
			t.Fatalf("failed to get x-only pubkey: %v", err)
		}

		msg := make([]byte, 32)

		// Sign with different aux_rand values
		auxRand1 := make([]byte, 32)
		auxRand2 := make([]byte, 32)
		for i := range auxRand1 {
			auxRand1[i] = byte(i)
			auxRand2[i] = byte(i + 1)
		}

		var sig1, sig2 [64]byte
		if err := SchnorrSign(sig1[:], msg, kp, auxRand1); err != nil {
			t.Fatalf("failed to sign: %v", err)
		}
		if err := SchnorrSign(sig2[:], msg, kp, auxRand2); err != nil {
			t.Fatalf("failed to sign: %v", err)
		}

		// Convert x-only pubkey to secp256k1_xonly_pubkey format
		var secp_xonly secp256k1_xonly_pubkey
		copy(secp_xonly.data[:], xonly.data[:])

		// Test both signatures with existing implementation
		existingResult1 := SchnorrVerify(sig1[:], msg, xonly)
		existingResult2 := SchnorrVerify(sig2[:], msg, xonly)

		// Test both signatures with new implementation
		newResult1 := secp256k1_schnorrsig_verify(ctx, sig1[:], msg, len(msg), &secp_xonly)
		newResult2 := secp256k1_schnorrsig_verify(ctx, sig2[:], msg, len(msg), &secp_xonly)

		// Compare results
		if existingResult1 != (newResult1 != 0) {
			t.Errorf("signature 1 results differ: existing=%v, new=%d", existingResult1, newResult1)
		}
		if existingResult2 != (newResult2 != 0) {
			t.Errorf("signature 2 results differ: existing=%v, new=%d", existingResult2, newResult2)
		}

		if !existingResult1 || !existingResult2 {
			t.Error("both signatures should verify")
		}
	})

	// Test case 7: Empty message
	t.Run("EmptyMessage", func(t *testing.T) {
		// Generate keypair
		kp, err := KeyPairGenerate()
		if err != nil {
			t.Fatalf("failed to generate keypair: %v", err)
		}
		defer kp.Clear()

		// Get x-only pubkey
		xonly, err := kp.XOnlyPubkey()
		if err != nil {
			t.Fatalf("failed to get x-only pubkey: %v", err)
		}

		// Create 32-byte message (all zeros)
		msg := make([]byte, 32)

		// Sign
		var sig [64]byte
		if err := SchnorrSign(sig[:], msg, kp, nil); err != nil {
			t.Fatalf("failed to sign: %v", err)
		}

		// Convert x-only pubkey to secp256k1_xonly_pubkey format
		var secp_xonly secp256k1_xonly_pubkey
		copy(secp_xonly.data[:], xonly.data[:])

		// Test existing implementation (old)
		existingResult := SchnorrVerifyOld(sig[:], msg, xonly)

		// Test new implementation (C-translated)
		newResult := SchnorrVerify(sig[:], msg, xonly)

		// Compare results
		if existingResult != newResult {
			t.Errorf("results differ: existing=%v, new=%v", existingResult, newResult)
		}

		if !existingResult {
			t.Error("signature verification failed for empty message")
		}
	})
}
