package appidentitykeydeclarationv1

import (
	"fmt"

	"github.com/pingcap-inc/nexuscrm-contract/pkg/appauthority"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/layoutroutingsecurityv1"
)

// VerifyPackageDeclarations structurally verifies a complete App package and
// extracts every v1 ProfileKey and RoleKey declaration. It does not verify a
// publisher signature, register a release, resolve namespace ownership, or
// admit a key to an organization identity ledger.
func VerifyPackageDeclarations(pkg appauthority.Package) (appauthority.VerifiedPackage, Declarations, error) {
	verified, err := appauthority.VerifyPackage(pkg)
	if err != nil {
		return appauthority.VerifiedPackage{}, Declarations{}, err
	}

	declarations := Declarations{
		Profiles: make([]ProfileDeclaration, 0),
		Roles:    make([]RoleDeclaration, 0),
	}
	seenProfiles := map[string]string{}
	seenRoles := map[string]string{}
	for index, component := range verified.Bundle.Components {
		switch component.ComponentKind {
		case ProfileComponentKind:
			declaration, declarationErr := verifyProfileDeclaration(verified, component, verified.ComponentBlobs[index].CanonicalBehavior)
			if declarationErr != nil {
				return appauthority.VerifiedPackage{}, Declarations{}, fmt.Errorf("Profile key declaration component[%d]: %w", index, declarationErr)
			}
			key := declaration.Key.NamespaceID + "\x00" + declaration.Key.LocalKey
			if existing, duplicate := seenProfiles[key]; duplicate {
				return appauthority.VerifiedPackage{}, Declarations{}, fmt.Errorf("Profile key declaration component[%d]: typed key is already declared by %s", index, existing)
			}
			seenProfiles[key] = declaration.DeclarationComponentID
			declarations.Profiles = append(declarations.Profiles, declaration)
		case RoleComponentKind:
			declaration, declarationErr := verifyRoleDeclaration(verified, component, verified.ComponentBlobs[index].CanonicalBehavior)
			if declarationErr != nil {
				return appauthority.VerifiedPackage{}, Declarations{}, fmt.Errorf("Role key declaration component[%d]: %w", index, declarationErr)
			}
			key := declaration.Key.NamespaceID + "\x00" + declaration.Key.LocalKey
			if existing, duplicate := seenRoles[key]; duplicate {
				return appauthority.VerifiedPackage{}, Declarations{}, fmt.Errorf("Role key declaration component[%d]: typed key is already declared by %s", index, existing)
			}
			seenRoles[key] = declaration.DeclarationComponentID
			declarations.Roles = append(declarations.Roles, declaration)
		}
	}
	return verified, declarations, nil
}

func verifyProfileDeclaration(verified appauthority.VerifiedPackage, component appauthority.Component, rawBehavior []byte) (ProfileDeclaration, error) {
	if err := validateDescriptor(component, ProfileComponentKind); err != nil {
		return ProfileDeclaration{}, err
	}
	key := layoutroutingsecurityv1.ProfileKey{NamespaceID: component.NamespaceID, LocalKey: component.BusinessKey}
	if err := layoutroutingsecurityv1.ValidateProfileKey(key); err != nil {
		return ProfileDeclaration{}, fmt.Errorf("typed key: %w", err)
	}
	if _, err := ParseCanonicalBehavior(rawBehavior); err != nil {
		return ProfileDeclaration{}, err
	}
	return ProfileDeclaration{
		AppID:                  verified.Manifest.AppID,
		AppReleaseDigest:       verified.AppReleaseDigest,
		Key:                    key,
		DeclarationComponentID: component.ComponentID,
		BehaviorDigest:         component.ContentDigest,
	}, nil
}

func verifyRoleDeclaration(verified appauthority.VerifiedPackage, component appauthority.Component, rawBehavior []byte) (RoleDeclaration, error) {
	if err := validateDescriptor(component, RoleComponentKind); err != nil {
		return RoleDeclaration{}, err
	}
	key := layoutroutingsecurityv1.RoleKey{NamespaceID: component.NamespaceID, LocalKey: component.BusinessKey}
	if err := layoutroutingsecurityv1.ValidateRoleKey(key); err != nil {
		return RoleDeclaration{}, fmt.Errorf("typed key: %w", err)
	}
	if _, err := ParseCanonicalBehavior(rawBehavior); err != nil {
		return RoleDeclaration{}, err
	}
	return RoleDeclaration{
		AppID:                  verified.Manifest.AppID,
		AppReleaseDigest:       verified.AppReleaseDigest,
		Key:                    key,
		DeclarationComponentID: component.ComponentID,
		BehaviorDigest:         component.ContentDigest,
	}, nil
}

func validateDescriptor(component appauthority.Component, componentKind string) error {
	if component.ComponentKind != componentKind {
		return fmt.Errorf("component_kind must equal %q", componentKind)
	}
	if component.ComponentFormatVersion != ComponentFormatVersion {
		return fmt.Errorf("component_format_version must equal %d", ComponentFormatVersion)
	}
	if component.DefinitionVersion != DefinitionVersion {
		return fmt.Errorf("definition_version must equal %q", DefinitionVersion)
	}
	expectedID := appauthority.ComponentID(component.NamespaceID, componentKind, component.BusinessKey)
	if component.ComponentID != expectedID {
		return fmt.Errorf("component_id does not match the derived declaration identity")
	}
	if component.LocalDependencies == nil || len(component.LocalDependencies) != 0 {
		return fmt.Errorf("local_dependencies must be present and empty")
	}
	if component.ExternalComponentRefs == nil || len(component.ExternalComponentRefs) != 0 {
		return fmt.Errorf("external_component_refs must be present and empty")
	}
	if component.OverridePolicy != appauthority.OverridePolicyReplace {
		return fmt.Errorf("override_policy must equal %q", appauthority.OverridePolicyReplace)
	}
	if component.RemovalPolicy != appauthority.RemovalPolicyBlockIfReferencedOrOverridden {
		return fmt.Errorf("removal_policy must equal %q", appauthority.RemovalPolicyBlockIfReferencedOrOverridden)
	}
	if err := appauthority.ValidateDigest(component.ContentDigest); err != nil {
		return fmt.Errorf("content_digest: %w", err)
	}
	return nil
}
