package catalogapp

import (
	"bytes"
	"fmt"

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

// verifiedReleaseComponentSet keeps one structurally verified App package with
// every Catalog-recognized, source-only component projection. The projections
// remain separate facts: a layout-bundle slot is not an identity declaration,
// and an identity declaration is not a namespace claim or local-ID mapping.
type verifiedReleaseComponentSet struct {
	packageFacts      appauthority.VerifiedPackage
	layoutBundleSlots []layoutbundleslotv1.Declaration
	identityKeyFacts  appidentitykeydeclarationv1.Declarations
}

// verifyReleaseComponentSet is the sole structural package read path for
// Catalog-recognized component grammars. Each neutral grammar owns its parser;
// this function only requires them to agree on the same canonical App package.
func verifyReleaseComponentSet(pkg appauthority.Package) (verifiedReleaseComponentSet, error) {
	packageWithSlots, layoutBundleSlots, err := layoutbundleslotv1.VerifyPackageDeclarations(pkg)
	if err != nil {
		return verifiedReleaseComponentSet{}, err
	}
	packageWithIdentityKeys, identityKeyFacts, err := appidentitykeydeclarationv1.VerifyPackageDeclarations(pkg)
	if err != nil {
		return verifiedReleaseComponentSet{}, err
	}
	if packageWithSlots.AppReleaseDigest != packageWithIdentityKeys.AppReleaseDigest ||
		!bytes.Equal(packageWithSlots.CanonicalManifest, packageWithIdentityKeys.CanonicalManifest) ||
		!bytes.Equal(packageWithSlots.CanonicalBundle, packageWithIdentityKeys.CanonicalBundle) {
		return verifiedReleaseComponentSet{}, fmt.Errorf("recognized component verification disagrees on the canonical App package")
	}
	return verifiedReleaseComponentSet{
		packageFacts:      packageWithSlots,
		layoutBundleSlots: layoutBundleSlots,
		identityKeyFacts:  cloneIdentityKeyDeclarations(identityKeyFacts),
	}, nil
}

func cloneIdentityKeyDeclarations(value appidentitykeydeclarationv1.Declarations) appidentitykeydeclarationv1.Declarations {
	return appidentitykeydeclarationv1.Declarations{
		Profiles: append([]appidentitykeydeclarationv1.ProfileDeclaration(nil), value.Profiles...),
		Roles:    append([]appidentitykeydeclarationv1.RoleDeclaration(nil), value.Roles...),
	}
}
