// @oagen-ignore-file

package workos

import (
	
	
	
	
	
	
	
	
)

// VaultEncryptResult is the result of a Vault.Encrypt call.
type VaultEncryptResult struct {
	// EncryptedData is the base64-encoded ciphertext (LEB128 header + encrypted keys + nonce + AES-GCM output).
	EncryptedData string
	// KeyContext is the encryption key context used for this operation.
	KeyContext map[string]string
	// EncryptedKeys is the base64-encoded encrypted key blob for later decryption via the API.
	EncryptedKeys string
}

// Encrypt generates a data key and encrypts data locally using AES-256-GCM.
func ( *VaultService) ( context.Context,  string,  map[string]string,  string,  ...RequestOption) (*VaultEncryptResult, error) {
	,  := .CreateDataKey(, &VaultCreateDataKeyParams{
		Context: ,
	}, ...)
	if  != nil {
		return nil, fmt.Errorf("workos: vault encrypt: failed to create data key: %w", )
	}

	,  := LocalEncrypt(, *, )
	if  != nil {
		return nil, fmt.Errorf("workos: vault encrypt: %w", )
	}

	return &VaultEncryptResult{
		EncryptedData: ,
		KeyContext:    .Context,
		EncryptedKeys: .EncryptedKeys,
	}, nil
}

// Decrypt decrypts locally encrypted data by first decrypting the data key via the API.
func ( *VaultService) ( context.Context,  string,  string,  ...RequestOption) (string, error) {
	,  := base64.StdEncoding.DecodeString()
	if  != nil {
		return "", fmt.Errorf("workos: vault decrypt: failed to base64-decode encrypted data: %w", )
	}

	, ,  := decodeLEB128()
	if  != nil {
		return "", fmt.Errorf("workos: vault decrypt: failed to decode LEB128 prefix: %w", )
	}

	if uint32(len()-) <  {
		return "", errors.New("workos: vault decrypt: encrypted data too short for declared key length")
	}

	 := [ : +int()]
	 := base64.StdEncoding.EncodeToString()

	,  := .CreateDecrypt(, &VaultCreateDecryptParams{
		Keys: ,
	}, ...)
	if  != nil {
		return "", fmt.Errorf("workos: vault decrypt: failed to decrypt data key: %w", )
	}

	,  := LocalDecrypt(, *, )
	if  != nil {
		return "", fmt.Errorf("workos: vault decrypt: %w", )
	}

	return , nil
}

// LocalEncrypt encrypts data with AES-256-GCM using a pre-fetched data key pair.
//
// Wire format (before base64): LEB128(len(encryptedKeys)) || encryptedKeys || nonce(12) || ciphertext+tag
func ( string,  CreateDataKeyResponse,  string) (string, error) {
	,  := base64.StdEncoding.DecodeString(.DataKey)
	if  != nil {
		return "", fmt.Errorf("failed to decode data key: %w", )
	}

	,  := base64.StdEncoding.DecodeString(.EncryptedKeys)
	if  != nil {
		return "", fmt.Errorf("failed to decode encrypted keys: %w", )
	}

	,  := aes.NewCipher()
	if  != nil {
		return "", fmt.Errorf("failed to create AES cipher: %w", )
	}

	,  := cipher.NewGCM()
	if  != nil {
		return "", fmt.Errorf("failed to create GCM: %w", )
	}

	 := make([]byte, .NonceSize()) // 12 bytes
	if ,  := io.ReadFull(rand.Reader, );  != nil {
		return "", fmt.Errorf("failed to generate nonce: %w", )
	}

	 := .Seal(nil, , []byte(), []byte())

	 := encodeLEB128(uint32(len()))
	 := make([]byte, 0, len()+len()+len()+len())
	 = append(, ...)
	 = append(, ...)
	 = append(, ...)
	 = append(, ...)

	return base64.StdEncoding.EncodeToString(), nil
}

// LocalDecrypt decrypts data with AES-256-GCM using a pre-fetched data key.
func ( string,  DecryptResponse,  string) (string, error) {
	,  := base64.StdEncoding.DecodeString()
	if  != nil {
		return "", fmt.Errorf("failed to base64-decode encrypted data: %w", )
	}

	, ,  := decodeLEB128()
	if  != nil {
		return "", fmt.Errorf("failed to decode LEB128 prefix: %w", )
	}

	 :=  + int()
	if +12 > len() {
		return "", errors.New("encrypted data too short: missing nonce")
	}

	 := [ : +12]
	 := [+12:]

	if len() == 0 {
		return "", errors.New("encrypted data too short: missing ciphertext")
	}

	,  := base64.StdEncoding.DecodeString(.DataKey)
	if  != nil {
		return "", fmt.Errorf("failed to decode data key: %w", )
	}

	,  := aes.NewCipher()
	if  != nil {
		return "", fmt.Errorf("failed to create AES cipher: %w", )
	}

	,  := cipher.NewGCM()
	if  != nil {
		return "", fmt.Errorf("failed to create GCM: %w", )
	}

	,  := .Open(nil, , , []byte())
	if  != nil {
		return "", fmt.Errorf("failed to decrypt: %w", )
	}

	return string(), nil
}

// encodeLEB128 encodes a uint32 as an unsigned LEB128 byte sequence.
func ( uint32) []byte {
	if  == 0 {
		return []byte{0}
	}
	var  []byte
	for  > 0 {
		 := byte( & 0x7f)
		 >>= 7
		if  > 0 {
			 |= 0x80
		}
		 = append(, )
	}
	return 
}

// decodeLEB128 decodes an unsigned LEB128 value from the start of buf.
// It returns the decoded value, the number of bytes consumed, and any error.
func ( []byte) (uint32, int, error) {
	var  uint32
	var  uint
	for  := 0;  < len(); ++ {
		 := []
		 |= uint32(&0x7f) << 
		if &0x80 == 0 {
			return ,  + 1, nil
		}
		 += 7
		if  >= 35 {
			return 0, 0, errors.New("LEB128 value too large for uint32")
		}
	}
	return 0, 0, errors.New("unexpected end of LEB128 data")
}