// Package secureconfig provides secure access to configuration secrets.
// It wraps sensitive configuration values in memguard-protected buffers
// to prevent secret leakage through memory dumps.
package secureconfig

import (
	"sync"

	"github.com/awnumar/memguard"

	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
)

// SecureConfigProvider provides secure access to configuration secrets.
// Secrets are stored in memguard LockedBuffers and wiped when no longer needed.
type SecureConfigProvider struct {
	mu sync.RWMutex

	// Cached secure buffers - created on first access
	jwtSecret      *memguard.LockedBuffer
	dbPassword     *memguard.LockedBuffer
	cachePassword  *memguard.LockedBuffer
	s3AccessKey    *memguard.LockedBuffer
	s3SecretKey    *memguard.LockedBuffer
	mailgunAPIKey  *memguard.LockedBuffer

	// Original config for initial loading
	cfg *config.Config
}

// NewSecureConfigProvider creates a new secure config provider from the given config.
// The original config secrets are copied to secure buffers and should be cleared
// from the original config after this call.
func NewSecureConfigProvider(cfg *config.Config) *SecureConfigProvider {
	provider := &SecureConfigProvider{
		cfg: cfg,
	}

	// Pre-load secrets into secure buffers
	provider.loadSecrets()

	return provider
}

// loadSecrets copies secrets from config into memguard buffers.
// SECURITY: Original config strings remain in memory but secure buffers provide
// additional protection for long-lived secret access.
func (p *SecureConfigProvider) loadSecrets() {
	p.mu.Lock()
	defer p.mu.Unlock()

	// JWT Secret
	if p.cfg.JWT.Secret != "" {
		p.jwtSecret = memguard.NewBufferFromBytes([]byte(p.cfg.JWT.Secret))
	}

	// Database Password
	if p.cfg.Database.Password != "" {
		p.dbPassword = memguard.NewBufferFromBytes([]byte(p.cfg.Database.Password))
	}

	// Cache Password
	if p.cfg.Cache.Password != "" {
		p.cachePassword = memguard.NewBufferFromBytes([]byte(p.cfg.Cache.Password))
	}

	// S3 Access Key
	if p.cfg.S3.AccessKey != "" {
		p.s3AccessKey = memguard.NewBufferFromBytes([]byte(p.cfg.S3.AccessKey))
	}

	// S3 Secret Key
	if p.cfg.S3.SecretKey != "" {
		p.s3SecretKey = memguard.NewBufferFromBytes([]byte(p.cfg.S3.SecretKey))
	}

	// Mailgun API Key
	if p.cfg.Mailgun.APIKey != "" {
		p.mailgunAPIKey = memguard.NewBufferFromBytes([]byte(p.cfg.Mailgun.APIKey))
	}
}

// JWTSecret returns the JWT secret as a secure byte slice.
// The returned bytes should not be stored - use immediately and let GC collect.
func (p *SecureConfigProvider) JWTSecret() []byte {
	p.mu.RLock()
	defer p.mu.RUnlock()

	if p.jwtSecret == nil || !p.jwtSecret.IsAlive() {
		return nil
	}
	return p.jwtSecret.Bytes()
}

// DatabasePassword returns the database password as a secure byte slice.
func (p *SecureConfigProvider) DatabasePassword() []byte {
	p.mu.RLock()
	defer p.mu.RUnlock()

	if p.dbPassword == nil || !p.dbPassword.IsAlive() {
		return nil
	}
	return p.dbPassword.Bytes()
}

// CachePassword returns the cache password as a secure byte slice.
func (p *SecureConfigProvider) CachePassword() []byte {
	p.mu.RLock()
	defer p.mu.RUnlock()

	if p.cachePassword == nil || !p.cachePassword.IsAlive() {
		return nil
	}
	return p.cachePassword.Bytes()
}

// S3AccessKey returns the S3 access key as a secure byte slice.
func (p *SecureConfigProvider) S3AccessKey() []byte {
	p.mu.RLock()
	defer p.mu.RUnlock()

	if p.s3AccessKey == nil || !p.s3AccessKey.IsAlive() {
		return nil
	}
	return p.s3AccessKey.Bytes()
}

// S3SecretKey returns the S3 secret key as a secure byte slice.
func (p *SecureConfigProvider) S3SecretKey() []byte {
	p.mu.RLock()
	defer p.mu.RUnlock()

	if p.s3SecretKey == nil || !p.s3SecretKey.IsAlive() {
		return nil
	}
	return p.s3SecretKey.Bytes()
}

// MailgunAPIKey returns the Mailgun API key as a secure byte slice.
func (p *SecureConfigProvider) MailgunAPIKey() []byte {
	p.mu.RLock()
	defer p.mu.RUnlock()

	if p.mailgunAPIKey == nil || !p.mailgunAPIKey.IsAlive() {
		return nil
	}
	return p.mailgunAPIKey.Bytes()
}

// Destroy securely wipes all cached secrets from memory.
// Should be called during application shutdown.
func (p *SecureConfigProvider) Destroy() {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.jwtSecret != nil && p.jwtSecret.IsAlive() {
		p.jwtSecret.Destroy()
	}
	if p.dbPassword != nil && p.dbPassword.IsAlive() {
		p.dbPassword.Destroy()
	}
	if p.cachePassword != nil && p.cachePassword.IsAlive() {
		p.cachePassword.Destroy()
	}
	if p.s3AccessKey != nil && p.s3AccessKey.IsAlive() {
		p.s3AccessKey.Destroy()
	}
	if p.s3SecretKey != nil && p.s3SecretKey.IsAlive() {
		p.s3SecretKey.Destroy()
	}
	if p.mailgunAPIKey != nil && p.mailgunAPIKey.IsAlive() {
		p.mailgunAPIKey.Destroy()
	}

	p.jwtSecret = nil
	p.dbPassword = nil
	p.cachePassword = nil
	p.s3AccessKey = nil
	p.s3SecretKey = nil
	p.mailgunAPIKey = nil
}

// Config returns the underlying config for non-secret access.
// Prefer using the specific secret accessor methods for sensitive data.
func (p *SecureConfigProvider) Config() *config.Config {
	return p.cfg
}
