package storage

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"path/filepath"
	"strings"
)

// ConfigAuthorityDigest returns a non-secret receipt for the object-location
// fields of a storage configuration. It does not replace Config as authority;
// consumers use it only to prove that a durable operation is being replayed
// against the same deployment mapping that originally selected its store.
func ConfigAuthorityDigest(config Config) (string, error) {
	type authority struct {
		Version        string `json:"version"`
		Provider       string `json:"provider"`
		FilesystemRoot string `json:"filesystemRoot,omitempty"`
		Bucket         string `json:"bucket"`
		Region         string `json:"region,omitempty"`
		Endpoint       string `json:"endpoint,omitempty"`
		KeyPrefix      string `json:"keyPrefix,omitempty"`
		UsePathStyle   bool   `json:"usePathStyle,omitempty"`
	}

	value := authority{
		Version:  "v1",
		Provider: strings.ToLower(strings.TrimSpace(config.Provider)),
		Bucket:   strings.TrimSpace(config.Bucket),
	}
	switch value.Provider {
	case ProviderFilesystem:
		root := strings.TrimSpace(config.FilesystemRoot)
		if root == "" {
			return "", errors.New("file storage filesystem root is empty")
		}
		value.FilesystemRoot = filepath.Clean(root)
	case ProviderS3:
		value.Region = strings.TrimSpace(config.Region)
		value.Endpoint = strings.TrimSpace(config.Endpoint)
		value.KeyPrefix = strings.Trim(strings.TrimSpace(config.KeyPrefix), "/")
		value.UsePathStyle = config.UsePathStyle
	default:
		return "", errors.New("file storage provider is unsupported")
	}
	if value.Bucket == "" {
		return "", errors.New("file storage bucket is empty")
	}
	encoded, err := json.Marshal(value)
	if err != nil {
		return "", err
	}
	sum := sha256.Sum256(encoded)
	return "sha256:" + hex.EncodeToString(sum[:]), nil
}
