package catalogconsumerauthority

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"regexp"
	"sort"
	"strings"
	"unicode"
	"unicode/utf8"

	consumerv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	commandv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commandv1"
	layoutauthoringv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/layoutauthoringv1"
	pagelayoutresolutionv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/pagelayoutresolutionv1"
)

const (
	ActiveInstallationState           = "ACTIVE"
	integrationBindingSetDigestDomain = "nexuscrm.catalog-integration-binding-set/v1"
	consumerGrantSetDigestDomain      = "nexuscrm.catalog-consumer-grant-set/v1"
	effectiveMetadataSetDigestDomain  = "nexuscrm.catalog-effective-metadata-set/v1"
)

var integrationBindingPackDigestPattern = regexp.MustCompile(
	`^nexus-pack-sha256-v1:[0-9a-f]{64}$`,
)

// IntegrationBindingSelection authorizes one workload to resolve one neutral
// fact from an exact immutable installed-pack generation. It is the common
// durable value model shared by Catalog publication and serving verification.
type IntegrationBindingSelection struct {
	AuthorizedWorkloadID string
	Binding              consumerv1.IntegrationBinding
}

// ConsumerGrant authorizes one admitted workload to read one closed Catalog
// consumer view. It is distinct from AppRelease engine capability grants.
type ConsumerGrant struct {
	AuthorizedWorkloadID string
	CapabilityID         string
}

type EffectiveMetadataComponent = consumerv1.EffectiveMetadataComponent

// ValidateIntegrationBindingSelection validates one neutral exact-generation
// reference without assigning workload or pack-generation authority.
func ValidateIntegrationBindingSelection(value IntegrationBindingSelection) error {
	if !validOpaque(value.AuthorizedWorkloadID, consumerv1.MaxIdentifierBytes) {
		return fmt.Errorf("authorized workload ID is invalid")
	}
	binding := value.Binding
	if !binding.Kind.Valid() ||
		!validOpaque(binding.OwnerPack, consumerv1.MaxIdentifierBytes) ||
		!validOpaque(binding.PackInstallationID, consumerv1.MaxIdentifierBytes) ||
		!integrationBindingPackDigestPattern.MatchString(binding.PackPayloadDigest) ||
		!validOpaque(binding.BusinessKey, consumerv1.MaxIdentifierBytes) ||
		binding.DefinitionVersion == 0 ||
		len(binding.CredentialRefs) > consumerv1.MaxCredentialRefCount ||
		!sort.StringsAreSorted(binding.CredentialRefs) {
		return fmt.Errorf("binding reference is invalid")
	}
	for index, credential := range binding.CredentialRefs {
		if !validOpaque(credential, consumerv1.MaxIdentifierBytes) ||
			(index > 0 && credential == binding.CredentialRefs[index-1]) {
			return fmt.Errorf("credential references must be sorted, unique, and valid")
		}
	}
	if binding.RuntimeCommand != nil {
		command := binding.RuntimeCommand
		if !commandv1.ValidCommandKind(command.CommandKind) ||
			command.PayloadFormatVersion == 0 ||
			!validOpaque(command.DefinitionRef, consumerv1.MaxIdentifierBytes) ||
			!validOpaque(command.DefinitionVersion, consumerv1.MaxIdentifierBytes) {
			return fmt.Errorf("Runtime command binding is invalid")
		}
	}
	return nil
}

// ComputeIntegrationBindingSetDigest returns the durable commitment over one
// canonical operation-bound binding selection. Callers must supply the exact
// sorted selection order; lifecycle admission owns shape validation.
func ComputeIntegrationBindingSetDigest(values []IntegrationBindingSelection) (string, error) {
	if values == nil {
		values = []IntegrationBindingSelection{}
	}
	encoded, err := json.Marshal(struct {
		Schema   string                        `json:"schema"`
		Bindings []IntegrationBindingSelection `json:"bindings"`
	}{
		Schema:   integrationBindingSetDigestDomain,
		Bindings: values,
	})
	if err != nil {
		return "", err
	}
	return digestPayload(encoded), nil
}

// ValidateConsumerGrant validates one closed Catalog disclosure grant without
// assigning workload authority. Callers must separately prove that the
// workload belongs to the operation or active installation.
func ValidateConsumerGrant(value ConsumerGrant) error {
	if err := ValidateWorkloadID(value.AuthorizedWorkloadID); err != nil {
		return err
	}
	if !IsConsumerCapability(value.CapabilityID) {
		return fmt.Errorf(
			"capability %q is not a closed Catalog consumer capability",
			value.CapabilityID,
		)
	}
	return nil
}

// ValidateWorkloadID validates the opaque workload identity grammar shared by
// Catalog operation admission and each closed consumer grant.
func ValidateWorkloadID(value string) error {
	if !validOpaque(value, consumerv1.MaxIdentifierBytes) {
		return fmt.Errorf("workload is invalid")
	}
	return nil
}

// IsConsumerCapability classifies only the capability fact. It deliberately
// does not inspect workload identity or operation authority.
func IsConsumerCapability(capabilityID string) bool {
	switch capabilityID {
	case consumerv1.AppMetadataCapabilityName,
		consumerv1.AppMetadataV2CapabilityName,
		consumerv1.AppMetadataV3CapabilityName,
		consumerv1.IntegrationBindingCapabilityName,
		layoutauthoringv1.CapabilityName,
		pagelayoutresolutionv1.CapabilityName:
		return true
	default:
		return false
	}
}

func ComputeEffectiveMetadataSetDigest(
	values []EffectiveMetadataComponent,
) (string, error) {
	if values == nil {
		values = []EffectiveMetadataComponent{}
	}
	encoded, err := json.Marshal(struct {
		Schema     string                       `json:"schema"`
		Components []EffectiveMetadataComponent `json:"components"`
	}{
		Schema:     effectiveMetadataSetDigestDomain,
		Components: values,
	})
	if err != nil {
		return "", err
	}
	return digestPayload(encoded), nil
}

// ComputeConsumerGrantSetDigest returns the durable commitment over one
// canonical operation-bound Catalog consumer grant set.
func ComputeConsumerGrantSetDigest(values []ConsumerGrant) (string, error) {
	if values == nil {
		values = []ConsumerGrant{}
	}
	encoded, err := json.Marshal(struct {
		Schema string          `json:"schema"`
		Grants []ConsumerGrant `json:"grants"`
	}{
		Schema: consumerGrantSetDigestDomain,
		Grants: values,
	})
	if err != nil {
		return "", err
	}
	return digestPayload(encoded), nil
}

func validOpaque(value string, maximum int) bool {
	if value == "" || len(value) > maximum || !utf8.ValidString(value) ||
		strings.TrimSpace(value) != value {
		return false
	}
	for _, character := range value {
		if unicode.IsControl(character) {
			return false
		}
	}
	return true
}

func digestPayload(encoded []byte) string {
	hash := sha256.New()
	_, _ = hash.Write([]byte{0})
	_, _ = hash.Write(encoded)
	return "sha256:" + hex.EncodeToString(hash.Sum(nil))
}
