package encryptor_wrapper

import (
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/pkgv2/secret/encrypt"
	secretprovider "github.com/tidbcloud/pkgv2/secret/provider"
)

type Encryptor interface {
	EncryptBase64(text string) (string, bizerr.BizError)
	DecryptBase64(encryptedEncoded string) (string, bizerr.BizError)

	/// EncryptBase64Inplace encrypts plain text in place.
	/// You should only use it over local temp variables.
	/// Avoid using it over some passed in structures, as it will modify
	/// the original data and may lead to pitfalls.
	EncryptBase64Inplace(text *string) bizerr.BizError

	/// DecryptBase64Inplace decrypts cipher text in place.
	/// You should only use it over local temp variables.
	/// Avoid using it over some passed in structures, as it will modify
	/// the original data and may lead to pitfalls.
	DecryptBase64Inplace(encryptedEncoded *string) bizerr.BizError
}

type encryptorImp struct {
	enc encrypt.Encryptor
}

func NewEncryptor(cmkARN string) (Encryptor, error) {
	enc, err := secretprovider.NewSecretEncryptor(cmkARN)
	if err != nil {
		return nil, err
	}
	return encryptorImp{
		enc: enc,
	}, nil
}

func (e encryptorImp) EncryptBase64(text string) (string, bizerr.BizError) {
	secretTxt, err := encrypt.EncryptBase64(e.enc, encrypt.Secret(text))
	if err != nil {
		return "", bizerr.WrapError(err, "encrypt failed")
	}
	return secretTxt, nil
}

// EncryptBase64Inplace encrypts the text in place, nil pointer and empty string are ignored
func (e encryptorImp) EncryptBase64Inplace(text *string) bizerr.BizError {
	if text != nil && *text != "" {
		secretTxt, err := encrypt.EncryptBase64(e.enc, encrypt.Secret(*text))
		if err != nil {
			return bizerr.WrapError(err, "encrypt failed")
		}
		*text = secretTxt
	}
	return nil
}

func (e encryptorImp) DecryptBase64(encryptedEncoded string) (string, bizerr.BizError) {
	plainText, err := encrypt.DecryptBase64(e.enc, encryptedEncoded)
	if err != nil {
		return "", bizerr.WrapError(err, "decrypt failed")
	}
	return string(plainText), nil
}

func (e encryptorImp) DecryptBase64Inplace(encryptedEncoded *string) bizerr.BizError {
	if encryptedEncoded != nil && *encryptedEncoded != "" {
		plainText, err := encrypt.DecryptBase64(e.enc, *encryptedEncoded)
		if err != nil {
			return bizerr.WrapError(err, "decrypt failed")
		}
		*encryptedEncoded = string(plainText)
	}
	return nil
}
