// Package memutil provides utilities for secure memory handling.
// These utilities help prevent sensitive data from remaining in memory
// after use, protecting against memory dump attacks.
package memutil

import (
	"crypto/subtle"

	"github.com/awnumar/memguard"

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

// WipeString overwrites a string's backing array with zeros and clears the string.
// Note: This only works if the string variable is the only reference to the data.
// For better security, use SecureString instead of plain strings for sensitive data.
func WipeString(s *string) {
	if s == nil || *s == "" {
		return
	}
	// Convert to byte slice and wipe
	// Note: This creates a copy, but we wipe what we can
	bytes := []byte(*s)
	memguard.WipeBytes(bytes)
	*s = ""
}

// SecureCompareStrings performs constant-time comparison of two strings.
// This prevents timing attacks when comparing secrets.
func SecureCompareStrings(a, b string) bool {
	return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
}

// SecureCompareBytes performs constant-time comparison of two byte slices.
// If wipeAfter is true, both slices are wiped after comparison.
func SecureCompareBytes(a, b []byte, wipeAfter bool) bool {
	if wipeAfter {
		defer memguard.WipeBytes(a)
		defer memguard.WipeBytes(b)
	}
	return subtle.ConstantTimeCompare(a, b) == 1
}

// WithSecureBytes executes a function with secure byte handling.
// The bytes are automatically wiped after the function returns.
func WithSecureBytes(data []byte, fn func([]byte) error) error {
	defer memguard.WipeBytes(data)
	return fn(data)
}

// WithSecureString executes a function with secure string handling.
// The SecureString is automatically wiped after the function returns.
func WithSecureString(str string, fn func(*sstring.SecureString) error) error {
	secure, err := sstring.NewSecureString(str)
	if err != nil {
		return err
	}
	defer secure.Wipe()
	return fn(secure)
}

// CloneAndWipe creates a copy of data and wipes the original.
// Useful when you need to pass data to a function that will store it,
// but want to ensure the original is wiped.
func CloneAndWipe(data []byte) []byte {
	if data == nil {
		return nil
	}
	clone := make([]byte, len(data))
	copy(clone, data)
	memguard.WipeBytes(data)
	return clone
}

// SecureZero overwrites memory with zeros.
// This is a convenience wrapper around memguard.WipeBytes.
func SecureZero(data []byte) {
	memguard.WipeBytes(data)
}

// WipeSecureString wipes a SecureString if it's not nil.
// This is a nil-safe convenience wrapper.
func WipeSecureString(s *sstring.SecureString) {
	if s != nil {
		s.Wipe()
	}
}

// WipeSecureBytes wipes a SecureBytes if it's not nil.
// This is a nil-safe convenience wrapper.
func WipeSecureBytes(s *sbytes.SecureBytes) {
	if s != nil {
		s.Wipe()
	}
}
