// Package benchmark provides performance benchmarks for memguard security operations.
package benchmark

import (
	"crypto/rand"
	"testing"

	"github.com/awnumar/memguard"
	"golang.org/x/crypto/argon2"

	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/security/securebytes"
	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/security/securestring"
)

// BenchmarkPlainStringAllocation benchmarks plain string allocation.
func BenchmarkPlainStringAllocation(b *testing.B) {
	for i := 0; i < b.N; i++ {
		s := "this is a test string with sensitive data"
		_ = s
	}
}

// BenchmarkSecureStringAllocation benchmarks SecureString allocation and cleanup.
func BenchmarkSecureStringAllocation(b *testing.B) {
	for i := 0; i < b.N; i++ {
		s, err := securestring.NewSecureString("this is a test string with sensitive data")
		if err != nil {
			b.Fatal(err)
		}
		s.Wipe()
	}
}

// BenchmarkPlainBytesAllocation benchmarks plain byte slice allocation.
func BenchmarkPlainBytesAllocation(b *testing.B) {
	for i := 0; i < b.N; i++ {
		data := make([]byte, 32)
		rand.Read(data)
		_ = data
	}
}

// BenchmarkSecureBytesAllocation benchmarks SecureBytes allocation and cleanup.
func BenchmarkSecureBytesAllocation(b *testing.B) {
	for i := 0; i < b.N; i++ {
		data := make([]byte, 32)
		rand.Read(data)
		sb, err := securebytes.NewSecureBytes(data)
		if err != nil {
			b.Fatal(err)
		}
		sb.Wipe()
	}
}

// BenchmarkPasswordHashing_Plain benchmarks password hashing without memguard.
func BenchmarkPasswordHashing_Plain(b *testing.B) {
	password := []byte("test_password_12345")
	salt := make([]byte, 16)
	rand.Read(salt)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = argon2.IDKey(password, salt, 3, 64*1024, 4, 32)
	}
}

// BenchmarkPasswordHashing_Secure benchmarks password hashing with memguard wiping.
func BenchmarkPasswordHashing_Secure(b *testing.B) {
	password, err := securestring.NewSecureString("test_password_12345")
	if err != nil {
		b.Fatal(err)
	}
	defer password.Wipe()

	salt := make([]byte, 16)
	rand.Read(salt)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		passwordBytes := password.Bytes()
		hash := argon2.IDKey(passwordBytes, salt, 3, 64*1024, 4, 32)
		memguard.WipeBytes(hash)
	}
}

// BenchmarkMemguardWipeBytes benchmarks the memguard.WipeBytes operation.
func BenchmarkMemguardWipeBytes(b *testing.B) {
	for i := 0; i < b.N; i++ {
		data := make([]byte, 32)
		rand.Read(data)
		memguard.WipeBytes(data)
	}
}

// BenchmarkMemguardWipeBytes_Large benchmarks wiping larger byte slices.
func BenchmarkMemguardWipeBytes_Large(b *testing.B) {
	for i := 0; i < b.N; i++ {
		data := make([]byte, 4096)
		rand.Read(data)
		memguard.WipeBytes(data)
	}
}

// BenchmarkLockedBuffer_Create benchmarks creating a memguard LockedBuffer.
func BenchmarkLockedBuffer_Create(b *testing.B) {
	for i := 0; i < b.N; i++ {
		buf := memguard.NewBuffer(32)
		buf.Destroy()
	}
}

// BenchmarkLockedBuffer_FromBytes benchmarks creating a LockedBuffer from bytes.
func BenchmarkLockedBuffer_FromBytes(b *testing.B) {
	data := make([]byte, 32)
	rand.Read(data)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		buf := memguard.NewBufferFromBytes(data)
		buf.Destroy()
	}
}

// BenchmarkJWTTokenGeneration_Plain simulates JWT token generation without security.
func BenchmarkJWTTokenGeneration_Plain(b *testing.B) {
	secret := make([]byte, 32)
	rand.Read(secret)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		// Simulate token signing
		_ = secret
	}
}

// BenchmarkJWTTokenGeneration_Secure simulates JWT token generation with memguard.
func BenchmarkJWTTokenGeneration_Secure(b *testing.B) {
	secret := make([]byte, 32)
	rand.Read(secret)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		secretCopy := make([]byte, len(secret))
		copy(secretCopy, secret)
		// Simulate token signing
		_ = secretCopy
		memguard.WipeBytes(secretCopy)
	}
}

// Run benchmarks with:
// go test -bench=. -benchmem ./pkg/security/benchmark/
