package resource

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"sort"
)

// CanonicalGiftConfigsJSON produces the immutable semantic bytes stored with a pinned gift entitlement.
// A resource can back more than one gift ID, so the promise contains every gift that was sendable at pin time.
func CanonicalGiftConfigsJSON(configs []GiftConfig) ([]byte, error) {
	return json.Marshal(canonicalGiftConfigs(configs))
}

func GiftConfigsContentHash(configs []GiftConfig) (string, error) {
	body, err := CanonicalGiftConfigsJSON(configs)
	if err != nil {
		return "", err
	}
	sum := sha256.Sum256(body)
	return hex.EncodeToString(sum[:]), nil
}

func canonicalGiftConfigs(configs []GiftConfig) []GiftConfig {
	if len(configs) == 0 {
		return nil
	}
	canonical := append([]GiftConfig(nil), configs...)
	for index := range canonical {
		canonical[index].EffectTypes = append([]string(nil), canonical[index].EffectTypes...)
		sort.Strings(canonical[index].EffectTypes)
		canonical[index].RegionIDs = append([]int64(nil), canonical[index].RegionIDs...)
		sort.Slice(canonical[index].RegionIDs, func(left, right int) bool {
			return canonical[index].RegionIDs[left] < canonical[index].RegionIDs[right]
		})
		canonical[index].Resource.UsageScopes = append([]string(nil), canonical[index].Resource.UsageScopes...)
		sort.Strings(canonical[index].Resource.UsageScopes)
	}
	sort.SliceStable(canonical, func(left, right int) bool {
		if canonical[left].GiftID != canonical[right].GiftID {
			return canonical[left].GiftID < canonical[right].GiftID
		}
		if canonical[left].ResourceID != canonical[right].ResourceID {
			return canonical[left].ResourceID < canonical[right].ResourceID
		}
		return canonical[left].PriceVersion < canonical[right].PriceVersion
	})
	return canonical
}
