//go:build !plan9 && !solaris && !js

package oracleobjectstorage

import (
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/oracle/oci-go-sdk/v65/common"
	"github.com/oracle/oci-go-sdk/v65/objectstorage"
)

const (
	sseDefaultAlgorithm = "AES256"
)

func getSha256(p []byte) []byte {
	h := sha256.New()
	h.Write(p)
	return h.Sum(nil)
}

func validateSSECustomerKeyOptions(opt *Options) error {
	if opt.SSEKMSKeyID != "" && (opt.SSECustomerKeyFile != "" || opt.SSECustomerKey != "") {
		return errors.New("oos: can't use vault sse_kms_key_id and local sse_customer_key at the same time")
	}
	if opt.SSECustomerKey != "" && opt.SSECustomerKeyFile != "" {
		return errors.New("oos: can't use sse_customer_key and sse_customer_key_file at the same time")
	}
	if opt.SSEKMSKeyID != "" {
		return nil
	}
	err := populateSSECustomerKeys(opt)
	if err != nil {
		return err
	}
	return nil
}

func populateSSECustomerKeys(opt *Options) error {
	if opt.SSECustomerKeyFile != "" {
		// Reads the base64-encoded AES key data from the specified file and computes its SHA256 checksum
		data, err := os.ReadFile(expandPath(opt.SSECustomerKeyFile))
		if err != nil {
			return fmt.Errorf("oos: error reading sse_customer_key_file: %v", err)
		}
		opt.SSECustomerKey = strings.TrimSpace(string(data))
	}
	if opt.SSECustomerKey != "" {
		decoded, err := base64.StdEncoding.DecodeString(opt.SSECustomerKey)
		if err != nil {
			return fmt.Errorf("oos: Could not decode sse_customer_key_file: %w", err)
		}
		sha256Checksum := base64.StdEncoding.EncodeToString(getSha256(decoded))
		if opt.SSECustomerKeySha256 == "" {
			opt.SSECustomerKeySha256 = sha256Checksum
		} else if opt.SSECustomerKeySha256 != sha256Checksum {
			return fmt.Errorf("the computed SHA256 checksum "+
				"(%v) of the key doesn't match the config entry sse_customer_key_sha256=(%v)",
				sha256Checksum, opt.SSECustomerKeySha256)
		}
		if opt.SSECustomerAlgorithm == "" {
			opt.SSECustomerAlgorithm = sseDefaultAlgorithm
		}
	}
	return nil
}

// https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/usingyourencryptionkeys.htm
func useBYOKPutObject(fs *Fs, request *objectstorage.PutObjectRequest) {
	if fs.opt.SSEKMSKeyID != "" {
		request.OpcSseKmsKeyId = common.String(fs.opt.SSEKMSKeyID)
	}
	if fs.opt.SSECustomerAlgorithm != "" {
		request.OpcSseCustomerAlgorithm = common.String(fs.opt.SSECustomerAlgorithm)
	}
	if fs.opt.SSECustomerKey != "" {
		request.OpcSseCustomerKey = common.String(fs.opt.SSECustomerKey)
	}
	if fs.opt.SSECustomerKeySha256 != "" {
		request.OpcSseCustomerKeySha256 = common.String(fs.opt.SSECustomerKeySha256)
	}
}

func useBYOKHeadObject(fs *Fs, request *objectstorage.HeadObjectRequest) {
	if fs.opt.SSECustomerAlgorithm != "" {
		request.OpcSseCustomerAlgorithm = common.String(fs.opt.SSECustomerAlgorithm)
	}
	if fs.opt.SSECustomerKey != "" {
		request.OpcSseCustomerKey = common.String(fs.opt.SSECustomerKey)
	}
	if fs.opt.SSECustomerKeySha256 != "" {
		request.OpcSseCustomerKeySha256 = common.String(fs.opt.SSECustomerKeySha256)
	}
}

func useBYOKGetObject(fs *Fs, request *objectstorage.GetObjectRequest) {
	if fs.opt.SSECustomerAlgorithm != "" {
		request.OpcSseCustomerAlgorithm = common.String(fs.opt.SSECustomerAlgorithm)
	}
	if fs.opt.SSECustomerKey != "" {
		request.OpcSseCustomerKey = common.String(fs.opt.SSECustomerKey)
	}
	if fs.opt.SSECustomerKeySha256 != "" {
		request.OpcSseCustomerKeySha256 = common.String(fs.opt.SSECustomerKeySha256)
	}
}

func useBYOKCopyObject(fs *Fs, request *objectstorage.CopyObjectRequest) {
	if fs.opt.SSEKMSKeyID != "" {
		request.OpcSseKmsKeyId = common.String(fs.opt.SSEKMSKeyID)
	}
	if fs.opt.SSECustomerAlgorithm != "" {
		request.OpcSseCustomerAlgorithm = common.String(fs.opt.SSECustomerAlgorithm)
	}
	if fs.opt.SSECustomerKey != "" {
		request.OpcSseCustomerKey = common.String(fs.opt.SSECustomerKey)
	}
	if fs.opt.SSECustomerKeySha256 != "" {
		request.OpcSseCustomerKeySha256 = common.String(fs.opt.SSECustomerKeySha256)
	}
}