package packs

import (
	"fmt"
	"strings"

	cp "github.com/pingcap-inc/nexuscrm-contract/pkg/controlplane"
)

func validateManagedLifecycleBaseRegistration(registration cp.ComponentKindRegistration, lifecycle cp.ComponentManagedLifecycleRegistration) error {
	if lifecycle.Kind() != registration.Contract.Kind {
		return fmt.Errorf("lifecycle kind %q does not match registration", lifecycle.Kind())
	}
	if err := validateManagedComponentRegistrationShape(registration); err != nil {
		return err
	}
	return validateComponentRegistrationDescriptor(registration)
}

func validateManagedComponentRegistrationShape(registration cp.ComponentKindRegistration) error {
	kind := string(registration.Contract.Kind)
	if kind == "" || strings.TrimSpace(kind) != kind || registration.Capability.Kind != registration.Contract.Kind {
		return fmt.Errorf("managed component registration kind is incomplete or inconsistent")
	}
	if !registration.Capability.Installable {
		return fmt.Errorf("managed component %s is not installable", kind)
	}
	if registration.Contract.OwnerDiscriminator != cp.ComponentOwnerStrategyOwnerPack && registration.Contract.OwnerDiscriminator != cp.ComponentOwnerStrategySource {
		return fmt.Errorf("managed component %s has unsupported owner discriminator %q", kind, registration.Contract.OwnerDiscriminator)
	}
	if len(registration.Contract.Manageabilities) == 0 || !sameComponentManageabilities(registration.Contract.Manageabilities, registration.Capability.Manageabilities) {
		return fmt.Errorf("managed component %s manageabilities are empty or inconsistent", kind)
	}
	seenTables := make(map[string]struct{}, len(registration.Contract.WriteSet))
	for _, surface := range registration.Contract.WriteSet {
		if err := validateComponentSQLIdentifier(surface.Table); err != nil {
			return fmt.Errorf("managed component %s write set: %w", kind, err)
		}
		if surface.Fact == "" || strings.TrimSpace(surface.Fact) != surface.Fact {
			return fmt.Errorf("managed component %s write set fact %q is not canonical", kind, surface.Fact)
		}
		if _, exists := seenTables[strings.ToLower(surface.Table)]; exists {
			return fmt.Errorf("managed component %s claims table %q more than once", kind, surface.Table)
		}
		seenTables[strings.ToLower(surface.Table)] = struct{}{}
	}
	if len(seenTables) == 0 {
		return fmt.Errorf("managed component %s write set is required", kind)
	}
	return nil
}
