package secrets

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"io"
	"log/slog"
)

type Secrets struct {
	Logger        *slog.Logger
	EncryptionKey []byte
}

func New(logger *slog.Logger, key []byte) *Secrets {
	return &Secrets{
		Logger:        logger,
		EncryptionKey: key,
	}
}

// Encrypt function that encrypts data using AES256-GCM and returns base64 encoded ciphertext
func (s *Secrets) Encrypt(plainText []byte) (string, error) {
	block, err := aes.NewCipher(s.EncryptionKey)
	if err != nil {
		return "", err
	}

	// Create a new GCM cipher
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// Create a nonce
	nonce := make([]byte, gcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	// Encrypt the plaintext using AES256-GCM
	cipherText := gcm.Seal(nonce, nonce, plainText, nil)

	// Return the base64 encoded ciphertext
	return base64.StdEncoding.EncodeToString(cipherText), nil
}

// Decrypt function that decrypts base64 encoded AES256-GCM ciphertext
func (s *Secrets) Decrypt(base64CipherText string) ([]byte, error) {
	// Decode the base64 ciphertext
	cipherText, err := base64.StdEncoding.DecodeString(base64CipherText)
	if err != nil {
		return nil, err
	}

	block, err := aes.NewCipher(s.EncryptionKey)
	if err != nil {
		return nil, err
	}

	// Create a new GCM cipher
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	// Extract the nonce from the ciphertext
	nonceSize := gcm.NonceSize()
	nonce, cipherText := cipherText[:nonceSize], cipherText[nonceSize:]

	// Decrypt the ciphertext
	plainText, err := gcm.Open(nil, nonce, cipherText, nil)
	if err != nil {
		return nil, err
	}

	return plainText, nil
}
