package appauthority

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"strconv"
)

const (
	componentIDDomain     = "nexuscrm.app-component-id.v1\x00"
	componentDigestDomain = "nexuscrm.app-component.v1\x00"
	metadataBundleDomain  = "nexuscrm.metadata-bundle.v1\x00"
	appReleaseDomain      = "nexuscrm.app-release.v1\x00"
	zeroDigest            = "sha256:0000000000000000000000000000000000000000000000000000000000000000"
)

func ComponentID(namespaceID, componentKind, businessKey string) string {
	return digestBytes([]byte(componentIDDomain + namespaceID + "\x00" + componentKind + "\x00" + businessKey))
}

func ComponentDigest(componentKind string, componentFormatVersion uint32, canonicalBehavior []byte) (string, error) {
	if err := validateNamedID("component kind", componentKind, 2, true); err != nil {
		return "", err
	}
	if componentFormatVersion == 0 {
		return "", fmt.Errorf("component format version must be positive")
	}
	if len(canonicalBehavior) == 0 {
		return "", fmt.Errorf("canonical component behavior bytes are required")
	}
	prefix := componentDigestDomain + componentKind + "\x00" + strconv.FormatUint(uint64(componentFormatVersion), 10) + "\x00"
	return digestParts([]byte(prefix), canonicalBehavior), nil
}

func MetadataBundleDigest(bundle MetadataBundle, manifest AppManifest) (string, error) {
	canonical, err := CanonicalMetadataBundle(bundle, manifest)
	if err != nil {
		return "", err
	}
	return digestParts([]byte(metadataBundleDomain), canonical), nil
}

func AppReleaseDigest(manifest AppManifest) (string, error) {
	canonical, err := CanonicalAppManifest(manifest)
	if err != nil {
		return "", err
	}
	return digestParts([]byte(appReleaseDomain), canonical), nil
}

func digestParts(parts ...[]byte) string {
	hash := sha256.New()
	for _, part := range parts {
		_, _ = hash.Write(part)
	}
	return "sha256:" + hex.EncodeToString(hash.Sum(nil))
}

func digestBytes(value []byte) string { return digestParts(value) }
