package catalogreconcile

import (
	"context"
	"encoding/json"
	"slices"
	"strings"
	"testing"

	"github.com/nexuscrm/kernel/pkg/formula"
	"github.com/nexuscrm/metadata/catalogsnapshot"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/nexuscrm/shared/pkg/referenceidentity"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/appauthority"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/approvalir"
	consumerv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/approvalv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/auditlogv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commandv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/effectivepermissionsv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/filesv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/flowv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordmutationv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/reportv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/searchv1"
	"github.com/pingcap-inc/nexuscrm-controlplane/catalogapp"
)

func TestReadEffectiveMetadataPublishesL1FormulaFunctionsFromVerifiedAppRelease(t *testing.T) {
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: "metadata.pack.formula-function-bundle.v1", businessKey: "crm-formula-functions",
		behavior: l1FormulaFunctionBundleBehavior(),
	}})
	opportunity := validObject("Opportunity")
	opportunity.Fields = append(opportunity.Fields, models.FieldMetadata{
		ID: "field-opportunity-deployment", APIName: "Existing_Database_Deployment__c",
		Label: "Existing Database Deployment", Type: constants.FieldTypeMultiPicklist,
		PhysicalName: "existing_database_deployment", Createable: true, Updateable: true,
		Options: models.PicklistOptions{{Value: "TiDB", Label: "TiDB"}},
	})
	selection := MetadataSelection{
		OrgID: "org-test", AppInstallationID: "installation-test",
		RuntimeCapabilityID: recordmutationv1.CapabilityName,
		CatalogRevision:     7, SchemaGeneration: 8, EngineGeneration: 9,
	}
	effective, err := ReadEffectiveMetadata(
		context.Background(),
		func(ctx context.Context, fn func(context.Context) error) error {
			return fn(context.WithValue(ctx, transactionMarker{}, "one-snapshot"))
		},
		// Simulate a clean D3 install where the L1 AppRelease is verified but
		// its source pack has no separately selected active PackGeneration.
		&markedReader{t: t, objects: []*models.ObjectMetadata{opportunity}},
		selection,
		&release,
	)
	if err != nil {
		t.Fatal(err)
	}
	snapshotArtifact, err := catalogsnapshot.CompileEffectiveMetadata(effective)
	if err != nil {
		t.Fatal(err)
	}
	snapshot, err := catalogsnapshot.OpenCatalogSnapshot(snapshotArtifact)
	if err != nil {
		t.Fatal(err)
	}
	viewArtifact, err := catalogsnapshot.ProjectRuntimeMetadataView(
		snapshot,
		catalogsnapshot.ProjectionKey{
			AppInstallationID: selection.AppInstallationID,
			CapabilityID:      recordmutationv1.CapabilityName,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	view, err := catalogsnapshot.OpenRuntimeMetadataView(viewArtifact)
	if err != nil {
		t.Fatal(err)
	}
	engine, err := view.NewFormulaEngine()
	if err != nil {
		t.Fatal(err)
	}
	added, err := engine.Evaluate(`ADDMONTHS("2024-01-31", 1)`, &formula.Context{})
	if err != nil || added != "2024-02-29" {
		t.Fatalf("revision-bound ADDMONTHS result = %#v, %v; want 2024-02-29", added, err)
	}
	included, err := engine.Evaluate(`INCLUDES(Existing_Database_Deployment__c, "TiDB")`, &formula.Context{
		Record: map[string]interface{}{"Existing_Database_Deployment__c": `["TiDB"]`},
		Schema: opportunity,
	})
	if err != nil || included != true {
		t.Fatalf("revision-bound INCLUDES result = %#v, %v; want true", included, err)
	}
}

func TestMergeReleaseFormulaFunctionBundlesComposesImmutableAuthorities(t *testing.T) {
	bundle, err := formula.ParseFunctionBundlePayload(l1FormulaFunctionBundleBehavior())
	if err != nil {
		t.Fatal(err)
	}
	input := catalogsnapshot.CompileInput{
		Lineage: catalogsnapshot.Lineage{CatalogRevision: 7},
		FormulaFunctionBundles: []catalogsnapshot.FormulaFunctionBundleInput{{
			CatalogRevision: 7,
			Bundle:          bundle,
		}},
	}
	if err := mergeReleaseFormulaFunctionBundles(&input, []formula.FunctionBundle{bundle}); err != nil {
		t.Fatalf("merge exact duplicate: %v", err)
	}
	if len(input.FormulaFunctionBundles) != 1 {
		t.Fatalf("exact duplicate produced %d bundles, want 1", len(input.FormulaFunctionBundles))
	}

	conflicting := formula.CloneFunctionBundles([]formula.FunctionBundle{bundle})[0]
	conflicting.Functions[0].MaxArgs++
	if err := mergeReleaseFormulaFunctionBundles(&input, []formula.FunctionBundle{conflicting}); err == nil ||
		!strings.Contains(err.Error(), `formula function "INCLUDES" disagrees`) {
		t.Fatalf("conflicting immutable definitions error = %v", err)
	}
}

func TestReadPlatformReleaseDefinitionsRejectsUnsupportedFormulaComponent(t *testing.T) {
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: "metadata.pack.formula-function-bundle.v1", businessKey: "crm-formula-functions",
		formatVersion: 2,
		behavior:      l1FormulaFunctionBundleBehavior(),
	}})
	_, err := readPlatformReleaseDefinitions(&release, MetadataSelection{
		RuntimeCapabilityID: recordmutationv1.CapabilityName,
	})
	if err == nil || !strings.Contains(err.Error(), "unsupported format version 2") {
		t.Fatalf("unsupported formula component error = %v", err)
	}
}

func l1FormulaFunctionBundleBehavior() []byte {
	return []byte(`{
		"functions": [
			{
				"name": "INCLUDES",
				"minArgs": 2,
				"maxArgs": 2,
				"sqlLowering": "multipicklist_contains_all",
				"return": {"kind": "fixed", "type": "boolean"},
				"args": [
					{"type": "string", "nullable": true},
					{"type": "string", "nullable": true}
				],
				"evaluator": {
					"kind": "formula_expr_v1",
					"params": ["field", "value"],
					"body": "INCLUDES(field, value)"
				}
			},
			{
				"name": "ADDMONTHS",
				"minArgs": 2,
				"maxArgs": 2,
				"return": {"kind": "fixed", "type": "date"},
				"args": [
					{"dateLikeLiteral": true},
					{"type": "number"}
				],
				"evaluator": {
					"kind": "formula_expr_v1",
					"params": ["date", "months"],
					"body": "__DATE_ADD_MONTHS__(date, months)"
				}
			}
		]
	}`)
}

func TestReadEffectiveMetadataPublishesReportAndCommandFromAppRelease(t *testing.T) {
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{
		{
			kind: reportReleaseComponentKind, businessKey: "work-items",
			behavior: []byte(`{"ID":"work-items","Name":"Work Items","SourceObject":"WorkItem","SourceRef":"WorkItem","DisplayMode":"TABULAR","Columns":["Id"],"Filters":[],"Grouping":[],"Aggregates":[]}`),
		},
		{
			kind: commandReleaseComponentKind, businessKey: "provider-event",
			behavior: []byte(`{"commandKind":"provider.event","payloadFormatVersion":1}`),
		},
	})
	selection := MetadataSelection{
		OrgID: "org-test", AppInstallationID: "installation-test",
		RuntimeCapabilityIDs: []string{
			reportv1.CapabilityName,
			commandv1.CapabilityName,
		},
		IntegrationBindings: []catalogapp.IntegrationBindingSelection{{
			AuthorizedWorkloadID: "integration-service",
			Binding: consumerv1.IntegrationBinding{
				OwnerPack: "connector-pack",
				RuntimeCommand: &consumerv1.RuntimeCommandBinding{
					CommandKind:          "provider.event",
					PayloadFormatVersion: 1,
					DefinitionRef:        "ProviderEvent",
					DefinitionVersion:    "flow-version-1",
				},
			},
		}},
		CatalogRevision: 7, SchemaGeneration: 8, EngineGeneration: 9,
	}
	effective, err := ReadEffectiveMetadata(
		context.Background(),
		func(ctx context.Context, fn func(context.Context) error) error {
			return fn(context.WithValue(ctx, transactionMarker{}, "one-snapshot"))
		},
		&markedReader{t: t, objects: []*models.ObjectMetadata{validObject("WorkItem")}},
		selection,
		&release,
	)
	if err != nil {
		t.Fatal(err)
	}
	var document struct {
		Reports []struct {
			ComponentID string `json:"componentId"`
			ID          string `json:"id"`
		} `json:"reports"`
		Commands []struct {
			ComponentID       string `json:"componentId"`
			CommandKind       string `json:"commandKind"`
			ExecutionBindings []struct {
				AuthorizedWorkloadID string `json:"authorizedWorkloadId"`
				DefinitionRef        string `json:"definitionRef"`
				DefinitionVersion    string `json:"definitionVersion"`
				ContextNamespace     string `json:"contextNamespace"`
			} `json:"executionBindings"`
		} `json:"commandRegistrations"`
		Projections []struct {
			CapabilityID           string   `json:"capabilityId"`
			ObjectAPINames         []string `json:"objectApiNames"`
			DefinitionComponentIDs []string `json:"definitionComponentIds"`
		} `json:"runtimeProjections"`
	}
	if err := json.Unmarshal(effective.Bytes(), &document); err != nil {
		t.Fatal(err)
	}
	if len(document.Reports) != 1 || document.Reports[0].ID != "work-items" ||
		len(document.Commands) != 1 || document.Commands[0].CommandKind != "provider.event" {
		t.Fatalf("published release definitions = %#v / %#v", document.Reports, document.Commands)
	}
	if bindings := document.Commands[0].ExecutionBindings; len(bindings) != 1 ||
		bindings[0].AuthorizedWorkloadID != "integration-service" ||
		bindings[0].DefinitionRef != "ProviderEvent" ||
		bindings[0].DefinitionVersion != "flow-version-1" ||
		bindings[0].ContextNamespace != "connector-pack" {
		t.Fatalf("published command execution bindings = %#v", bindings)
	}
	for _, projection := range document.Projections {
		if len(projection.DefinitionComponentIDs) != 1 {
			t.Fatalf("projection %q definition selection = %#v", projection.CapabilityID, projection)
		}
		if projection.CapabilityID == commandv1.CapabilityName &&
			len(projection.ObjectAPINames) != 0 {
			t.Fatalf("command projection gained object authority: %#v", projection)
		}
	}
	snapshotArtifact, err := catalogsnapshot.CompileEffectiveMetadata(effective)
	if err != nil {
		t.Fatal(err)
	}
	snapshot, err := catalogsnapshot.OpenCatalogSnapshot(snapshotArtifact)
	if err != nil {
		t.Fatal(err)
	}
	viewArtifact, err := catalogsnapshot.ProjectRuntimeMetadataView(
		snapshot,
		catalogsnapshot.ProjectionKey{
			AppInstallationID: selection.AppInstallationID,
			CapabilityID:      commandv1.CapabilityName,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	view, err := catalogsnapshot.OpenRuntimeMetadataView(viewArtifact)
	if err != nil {
		t.Fatal(err)
	}
	namespace, ok := view.CommandExecutionContext(
		"provider.event",
		1,
		"integration-service",
		"ProviderEvent",
		"flow-version-1",
	)
	if !ok || namespace != "connector-pack" {
		t.Fatalf("projected command execution context = %q, %v", namespace, ok)
	}
	if err := view.VerifySource(snapshot); err != nil {
		t.Fatalf("projected command view source: %v", err)
	}
}

func TestReadEffectiveMetadataPublishesApprovalProfilesFromAppRelease(t *testing.T) {
	behavior := approvalReleaseBehavior(t, "WorkItem", "PrimaryReview")
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: approvalReleaseComponentKind, businessKey: "WorkItem/PrimaryReview",
		behavior: behavior,
	}})
	componentID := release.Package.Bundle.Components[0].ComponentID
	selection := MetadataSelection{
		OrgID: "org-test", AppInstallationID: "installation-test",
		RuntimeCapabilityIDs: []string{
			approvalv1.ExecuteCapabilityName,
			approvalv1.ReadCapabilityName,
			queryv1.CapabilityName,
		},
		CatalogRevision: 7, SchemaGeneration: 8, EngineGeneration: 9,
	}
	effective, err := ReadEffectiveMetadata(
		context.Background(),
		func(ctx context.Context, fn func(context.Context) error) error {
			return fn(context.WithValue(ctx, transactionMarker{}, "one-snapshot"))
		},
		&markedReader{
			t: t, objects: []*models.ObjectMetadata{
				validObject("WorkItem"),
				validObject("ProcessDefinition"),
				validObject("ProcessNode"),
			},
			flowDefinitions: []*models.FlowDefinition{{
				Id: "definition-approval-only", DeveloperName: "ApprovalOnlyFlow",
				ProcessType: "AutoLaunchedFlow", ActiveVersionId: "version-approval-only",
			}},
			flowVersions: map[string][]*models.FlowVersion{
				"definition-approval-only": {{
					Id: "version-approval-only", DefinitionId: "definition-approval-only",
					VersionNumber: 1, Status: models.FlowStatusActive,
					ProcessType: "AutoLaunchedFlow", Source: "standard",
					MetadataRaw: []byte(`{"status":"Active","runAtomically":true,"start":{}}`),
				}},
			},
		},
		selection,
		&release,
	)
	if err != nil {
		t.Fatal(err)
	}
	snapshotArtifact, err := catalogsnapshot.CompileEffectiveMetadata(effective)
	if err != nil {
		t.Fatal(err)
	}
	snapshot, err := catalogsnapshot.OpenCatalogSnapshot(snapshotArtifact)
	if err != nil {
		t.Fatal(err)
	}
	for capability, wantProfile := range map[string]catalogsnapshot.ProjectionProfile{
		approvalv1.ExecuteCapabilityName: catalogsnapshot.ProjectionApprovalExecutionV1,
		approvalv1.ReadCapabilityName:    catalogsnapshot.ProjectionApprovalReadV1,
	} {
		t.Run(capability, func(t *testing.T) {
			artifact, err := catalogsnapshot.ProjectRuntimeMetadataView(snapshot, catalogsnapshot.ProjectionKey{
				AppInstallationID: selection.AppInstallationID,
				CapabilityID:      capability,
			})
			if err != nil {
				t.Fatal(err)
			}
			view, err := catalogsnapshot.OpenRuntimeMetadataView(artifact)
			if err != nil {
				t.Fatal(err)
			}
			if view.Profile() != wantProfile {
				t.Fatalf("profile = %q, want %q", view.Profile(), wantProfile)
			}
			definition, ok := view.ApprovalDefinition(componentID)
			if !ok || definition.ObjectAPIName != "WorkItem" ||
				definition.DeveloperName != "PrimaryReview" || !definition.Definition.Active {
				t.Fatalf("projected approval definition = %#v, %t", definition, ok)
			}
			if err := view.VerifySource(snapshot); err != nil {
				t.Fatalf("projected approval view source: %v", err)
			}
			flow, hasFlow := view.ActiveFlowVersion("ApprovalOnlyFlow")
			if capability == approvalv1.ExecuteCapabilityName {
				if !hasFlow || flow == nil || flow.Id != "version-approval-only" {
					t.Fatalf("approval execution Flow closure = %#v, %t", flow, hasFlow)
				}
			} else if hasFlow {
				t.Fatal("approval read projection inherited the execution-only Flow")
			}
		})
	}
	queryArtifact, err := catalogsnapshot.ProjectRuntimeMetadataView(snapshot, catalogsnapshot.ProjectionKey{
		AppInstallationID: selection.AppInstallationID,
		CapabilityID:      queryv1.CapabilityName,
	})
	if err != nil {
		t.Fatal(err)
	}
	queryView, err := catalogsnapshot.OpenRuntimeMetadataView(queryArtifact)
	if err != nil {
		t.Fatal(err)
	}
	resolution, err := queryView.ResolveReferenceIdentities(
		t.Context(), "ProcessDefinition", []string{componentID}, []string{"Id", "Name"},
	)
	if err != nil {
		t.Fatal(err)
	}
	identity := resolution.Identities[componentID]
	if identity.Disposition != referenceidentity.Immutable || identity.Record["Name"] != "Primary review" {
		t.Fatalf("query-safe Approval identity = %#v", identity)
	}
}

func TestValidateApprovalDefinitionAvailabilityUsesEveryImmutableSource(t *testing.T) {
	request := Request{Capabilities: []CapabilitySelection{{
		RuntimeCapabilityID: approvalv1.ExecuteCapabilityName,
	}}}
	emptyRelease := verifiedPlatformRelease(t, nil)
	if err := validateApprovalDefinitionAvailability(request, &emptyRelease); err == nil ||
		!strings.Contains(err.Error(), "requires at least one immutable definition") {
		t.Fatalf("missing Approval definition error = %v", err)
	}

	releaseDefinition := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: approvalReleaseComponentKind, businessKey: "WorkItem/PrimaryReview",
		behavior: approvalReleaseBehavior(t, "WorkItem", "PrimaryReview"),
	}})
	if err := validateApprovalDefinitionAvailability(request, &releaseDefinition); err != nil {
		t.Fatalf("AppRelease-owned Approval definition rejected: %v", err)
	}

	request.approvalPublication = &approvalPublicationSelection{
		bundle: &approvalir.PublicationBundle{Definitions: []approvalir.PublishedDefinition{{}}},
	}
	if err := validateApprovalDefinitionAvailability(request, &emptyRelease); err != nil {
		t.Fatalf("bound Approval publication rejected: %v", err)
	}
}

func TestReadEffectiveMetadataPublishesL1CompiledL2ApprovalBundle(t *testing.T) {
	behavior := approvalReleaseBehavior(t, "WorkItem", "PrimaryReview")
	var document approvalReleaseDocument
	if err := json.Unmarshal(behavior, &document); err != nil {
		t.Fatal(err)
	}
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: reportReleaseComponentKind, businessKey: "unrelated-report",
		behavior: []byte(`{"ID":"unrelated-report","Name":"Unrelated","SourceObject":"WorkItem","SourceRef":"WorkItem","DisplayMode":"TABULAR","Columns":["Id"],"Filters":[],"Grouping":[],"Aggregates":[]}`),
	}})
	selection := MetadataSelection{
		OrgID: "org-test", AppInstallationID: "installation-test",
		RuntimeCapabilityIDs: []string{
			approvalv1.ExecuteCapabilityName,
			approvalv1.ReadCapabilityName,
		},
		CatalogRevision: 7, SchemaGeneration: 8, EngineGeneration: 9,
		ApprovalDefinitions: []catalogsnapshot.ApprovalDefinitionInput{{
			CatalogRevision: 7, DefinitionID: "l2.WorkItem.PrimaryReview",
			ObjectAPIName: "WorkItem", DeveloperName: "PrimaryReview",
			Envelope: append([]byte(nil), document.DefinitionEnvelope...),
		}},
	}
	effective, err := ReadEffectiveMetadata(
		context.Background(),
		func(ctx context.Context, fn func(context.Context) error) error {
			return fn(context.WithValue(ctx, transactionMarker{}, "one-snapshot"))
		},
		&markedReader{
			t: t, objects: []*models.ObjectMetadata{validObject("WorkItem")},
			flowDefinitions: []*models.FlowDefinition{{
				Id: "definition-approval-only", DeveloperName: "ApprovalOnlyFlow",
				ProcessType: "AutoLaunchedFlow", ActiveVersionId: "version-approval-only",
			}},
			flowVersions: map[string][]*models.FlowVersion{
				"definition-approval-only": {{
					Id: "version-approval-only", DefinitionId: "definition-approval-only",
					VersionNumber: 1, Status: models.FlowStatusActive,
					ProcessType: "AutoLaunchedFlow", Source: "standard",
					MetadataRaw: []byte(`{"status":"Active","runAtomically":true,"start":{}}`),
				}},
			},
		},
		selection,
		&release,
	)
	if err != nil {
		t.Fatal(err)
	}
	snapshotArtifact, err := catalogsnapshot.CompileEffectiveMetadata(effective)
	if err != nil {
		t.Fatal(err)
	}
	snapshot, err := catalogsnapshot.OpenCatalogSnapshot(snapshotArtifact)
	if err != nil {
		t.Fatal(err)
	}
	artifact, err := catalogsnapshot.ProjectRuntimeMetadataView(snapshot, catalogsnapshot.ProjectionKey{
		AppInstallationID: selection.AppInstallationID,
		CapabilityID:      approvalv1.ExecuteCapabilityName,
	})
	if err != nil {
		t.Fatal(err)
	}
	view, err := catalogsnapshot.OpenRuntimeMetadataView(artifact)
	if err != nil {
		t.Fatal(err)
	}
	definition, ok := view.ApprovalDefinition("l2.WorkItem.PrimaryReview")
	if !ok || definition.ObjectAPIName != "WorkItem" || definition.DeveloperName != "PrimaryReview" {
		t.Fatalf("published L2 Approval definition = %#v, %t", definition, ok)
	}
}

func TestReadEffectiveMetadataRejectsApprovalWithMissingFlowDependency(t *testing.T) {
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: approvalReleaseComponentKind, businessKey: "WorkItem/PrimaryReview",
		behavior: approvalReleaseBehavior(t, "WorkItem", "PrimaryReview"),
	}})
	_, err := ReadEffectiveMetadata(
		context.Background(),
		func(ctx context.Context, fn func(context.Context) error) error {
			return fn(context.WithValue(ctx, transactionMarker{}, "one-snapshot"))
		},
		&markedReader{t: t, objects: []*models.ObjectMetadata{validObject("WorkItem")}},
		MetadataSelection{
			OrgID: "org-test", AppInstallationID: "installation-test",
			RuntimeCapabilityIDs: []string{approvalv1.ExecuteCapabilityName},
			CatalogRevision:      7, SchemaGeneration: 8, EngineGeneration: 9,
		},
		&release,
	)
	if err == nil || !strings.Contains(err.Error(), "ApprovalOnlyFlow") {
		t.Fatalf("missing Approval Flow dependency error = %v", err)
	}
}

func TestReadPlatformReleaseApprovalFailsClosed(t *testing.T) {
	if _, err := readPlatformReleaseDefinitions(nil, MetadataSelection{
		RuntimeCapabilityIDs: []string{approvalv1.ReadCapabilityName},
	}); err == nil || !strings.Contains(err.Error(), "verified AppRelease") {
		t.Fatalf("missing approval AppRelease error = %v", err)
	}

	tests := []struct {
		name          string
		formatVersion uint32
		behavior      []byte
		want          string
	}{
		{
			name: "unsupported component format", formatVersion: 2,
			behavior: approvalReleaseBehavior(t, "WorkItem", "PrimaryReview"),
			want:     "unsupported format version 2",
		},
		{
			name:     "unknown identity field",
			behavior: []byte(`{"objectApiName":"WorkItem","developerName":"PrimaryReview","definitionEnvelope":{},"fallback":true}`),
			want:     "unknown field",
		},
		{
			name:     "malformed envelope",
			behavior: []byte(`{"objectApiName":"WorkItem","developerName":"PrimaryReview","definitionEnvelope":{"schema":"nexuscrm.approval-definition/v1"}}`),
			want:     "invalid approval definition source digest",
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
				kind: approvalReleaseComponentKind, businessKey: "WorkItem/PrimaryReview",
				formatVersion: test.formatVersion, behavior: test.behavior,
			}})
			_, err := readPlatformReleaseDefinitions(&release, MetadataSelection{
				RuntimeCapabilityIDs: []string{approvalv1.ReadCapabilityName},
			})
			if err == nil || !strings.Contains(err.Error(), test.want) {
				t.Fatalf("read approval component error = %v, want %q", err, test.want)
			}
		})
	}

	malformed := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: approvalReleaseComponentKind, businessKey: "WorkItem/PrimaryReview",
		behavior: []byte(`{"not":"an approval component"}`),
	}})
	definitions, err := readPlatformReleaseDefinitions(&malformed, MetadataSelection{
		RuntimeCapabilityIDs: []string{filesv1.CapabilityName},
	})
	if err != nil || len(definitions.approvals) != 0 {
		t.Fatalf("unrequested approval component affected Files metadata: definitions=%#v error=%v", definitions, err)
	}
}

func TestReadEffectiveMetadataPublishesConsumerOnlyCommandProjection(t *testing.T) {
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: commandReleaseComponentKind, businessKey: "provider-event",
		behavior: []byte(
			`{"commandKind":"provider.event","payloadFormatVersion":1}`,
		),
	}})
	selection := MetadataSelection{
		OrgID:                "org-test",
		AppInstallationID:    "installation-test",
		RuntimeCapabilityIDs: []string{queryv1.CapabilityName},
		IntegrationBindings: []catalogapp.IntegrationBindingSelection{{
			AuthorizedWorkloadID: "integration-service",
			Binding: consumerv1.IntegrationBinding{
				OwnerPack: "connector-pack",
				RuntimeCommand: &consumerv1.RuntimeCommandBinding{
					CommandKind:          "provider.event",
					PayloadFormatVersion: 1,
					DefinitionRef:        "ProviderEvent",
					DefinitionVersion:    "flow-version-1",
				},
			},
		}},
		CatalogRevision:  7,
		SchemaGeneration: 8,
		EngineGeneration: 9,
	}
	effective, err := ReadEffectiveMetadata(
		context.Background(),
		func(ctx context.Context, fn func(context.Context) error) error {
			return fn(context.WithValue(
				ctx,
				transactionMarker{},
				"one-snapshot",
			))
		},
		&markedReader{
			t:       t,
			objects: []*models.ObjectMetadata{validObject("WorkItem")},
		},
		selection,
		&release,
	)
	if err != nil {
		t.Fatal(err)
	}
	snapshotArtifact, err := catalogsnapshot.CompileEffectiveMetadata(effective)
	if err != nil {
		t.Fatal(err)
	}
	snapshot, err := catalogsnapshot.OpenCatalogSnapshot(snapshotArtifact)
	if err != nil {
		t.Fatal(err)
	}
	viewArtifact, err := catalogsnapshot.ProjectRuntimeMetadataView(
		snapshot,
		catalogsnapshot.ProjectionKey{
			AppInstallationID: selection.AppInstallationID,
			CapabilityID:      commandv1.CapabilityName,
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	view, err := catalogsnapshot.OpenRuntimeMetadataView(viewArtifact)
	if err != nil {
		t.Fatal(err)
	}
	namespace, ok := view.CommandExecutionContext(
		"provider.event",
		1,
		"integration-service",
		"ProviderEvent",
		"flow-version-1",
	)
	if !ok || namespace != "connector-pack" {
		t.Fatalf("consumer-only command context = %q, %v", namespace, ok)
	}
	if err := view.VerifySource(snapshot); err != nil {
		t.Fatalf("consumer-only command view source: %v", err)
	}
}

func TestCommandExecutionBindingsRequireOneVerifiedAppReleaseRegistration(
	t *testing.T,
) {
	selection := MetadataSelection{
		RuntimeCapabilityIDs: []string{commandv1.CapabilityName},
		IntegrationBindings: []catalogapp.IntegrationBindingSelection{{
			AuthorizedWorkloadID: "integration-service",
			Binding: consumerv1.IntegrationBinding{
				OwnerPack: "connector-pack",
				RuntimeCommand: &consumerv1.RuntimeCommandBinding{
					CommandKind:          "unregistered.command",
					PayloadFormatVersion: 1,
					DefinitionRef:        "ProviderEvent",
					DefinitionVersion:    "flow-version-1",
				},
			},
		}},
	}
	_, err := commandExecutionBindings(
		[]platformReleaseCommand{{
			commandKind: "registered.command", payloadFormatVersion: 1,
		}},
		selection.IntegrationBindings,
	)
	if err == nil || !strings.Contains(err.Error(), "has no AppRelease registration") {
		t.Fatalf("unregistered Runtime command error = %v", err)
	}
}

func TestCommandExecutionBindingsDeduplicateOneExecutionAuthority(t *testing.T) {
	binding := consumerv1.IntegrationBinding{
		OwnerPack:   "connector-pack",
		BusinessKey: "route-a",
		RuntimeCommand: &consumerv1.RuntimeCommandBinding{
			CommandKind:          "provider.event",
			PayloadFormatVersion: 1,
			DefinitionRef:        "ProviderEvent",
			DefinitionVersion:    "flow-version-1",
		},
	}
	otherRoute := binding
	otherRoute.BusinessKey = "route-b"
	result, err := commandExecutionBindings(
		[]platformReleaseCommand{{
			commandKind: "provider.event", payloadFormatVersion: 1,
		}},
		[]catalogapp.IntegrationBindingSelection{
			{AuthorizedWorkloadID: "integration-service", Binding: binding},
			{AuthorizedWorkloadID: "integration-service", Binding: otherRoute},
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	key := commandRegistrationIdentity{kind: "provider.event", version: 1}
	if len(result) != 1 || len(result[key]) != 1 {
		t.Fatalf("deduplicated execution authority = %#v", result)
	}
}

func TestReadPlatformReleaseDefinitionsUsesOnlyVerifiedImmutableComponents(t *testing.T) {
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{
		{
			kind: reportReleaseComponentKind, businessKey: "pipeline",
			behavior: []byte(`{"ID":"pipeline","Name":"Pipeline","SourceObject":"Opportunity","SourceRef":"Opportunity","DisplayMode":"TABULAR","Columns":["Id"],"Filters":[],"Grouping":[],"Aggregates":[]}`),
		},
		{
			kind: commandReleaseComponentKind, businessKey: "provider-event",
			behavior: []byte(`{"commandKind":"provider.event","payloadFormatVersion":1}`),
		},
	})
	selection := MetadataSelection{RuntimeCapabilityIDs: []string{
		commandv1.CapabilityName,
		reportv1.CapabilityName,
	}}

	definitions, err := readPlatformReleaseDefinitions(&release, selection)
	if err != nil {
		t.Fatal(err)
	}
	if len(definitions.reports) != 1 || definitions.reports[0].definition.ID != "pipeline" ||
		len(definitions.commands) != 1 || definitions.commands[0].commandKind != "provider.event" ||
		definitions.commands[0].payloadFormatVersion != 1 {
		t.Fatalf("release definitions = %#v", definitions)
	}

	tampered := release
	tampered.ComponentBlobs = slices.Clone(release.ComponentBlobs)
	tampered.ComponentBlobs[0].CanonicalBehavior = []byte(`{"commandKind":"changed","payloadFormatVersion":1}`)
	if _, err := readPlatformReleaseDefinitions(&tampered, selection); err == nil {
		t.Fatal("tampered verified component was accepted")
	}
}

func TestReadPlatformReleaseDefinitionsRejectsAmbiguousJSON(t *testing.T) {
	release := verifiedPlatformRelease(t, []platformReleaseComponentFixture{{
		kind: commandReleaseComponentKind, businessKey: "provider-event",
		behavior: []byte(`{"commandKind":"provider.event","commandKind":"changed","payloadFormatVersion":1}`),
	}})
	selection := MetadataSelection{RuntimeCapabilityIDs: []string{commandv1.CapabilityName}}
	if _, err := readPlatformReleaseDefinitions(&release, selection); err == nil ||
		!strings.Contains(err.Error(), "duplicate object key") {
		t.Fatalf("ambiguous component error = %v", err)
	}
}

type platformReleaseComponentFixture struct {
	kind          string
	businessKey   string
	formatVersion uint32
	behavior      []byte
}

func verifiedPlatformRelease(
	t *testing.T,
	fixtures []platformReleaseComponentFixture,
) appauthority.VerifiedPackage {
	t.Helper()
	components := make([]appauthority.Component, 0, len(fixtures))
	behaviorByID := make(map[string][]byte, len(fixtures))
	for _, fixture := range fixtures {
		formatVersion := fixture.formatVersion
		if formatVersion == 0 {
			formatVersion = 1
		}
		digest, err := appauthority.ComponentDigest(fixture.kind, formatVersion, fixture.behavior)
		if err != nil {
			t.Fatal(err)
		}
		component := appauthority.Component{
			ComponentKind: fixture.kind, ComponentFormatVersion: formatVersion,
			NamespaceID: "io.example.app", BusinessKey: fixture.businessKey,
			DefinitionVersion: "1", LocalDependencies: []string{},
			ExternalComponentRefs: []appauthority.ExternalComponentRef{},
			OverridePolicy:        appauthority.OverridePolicyPreserveAuthorized,
			RemovalPolicy:         appauthority.RemovalPolicyBlockIfReferencedOrOverridden,
			ContentDigest:         digest,
		}
		component.ComponentID = appauthority.ComponentID(
			component.NamespaceID,
			component.ComponentKind,
			component.BusinessKey,
		)
		components = append(components, component)
		behaviorByID[component.ComponentID] = fixture.behavior
	}
	slices.SortFunc(components, func(left, right appauthority.Component) int {
		return strings.Compare(left.ComponentID, right.ComponentID)
	})
	blobs := make([]appauthority.ComponentBlob, len(components))
	for index, component := range components {
		blobs[index] = appauthority.ComponentBlob{
			ComponentID: component.ComponentID,
			CanonicalBehavior: append(
				[]byte(nil),
				behaviorByID[component.ComponentID]...,
			),
		}
	}
	bundle := appauthority.MetadataBundle{
		SchemaVersion: appauthority.MetadataBundleSchemaVersion,
		Components:    components,
	}
	requiredCapabilities := []string{
		commandv1.CapabilityName,
		reportv1.CapabilityName,
	}
	for _, fixture := range fixtures {
		if fixture.kind == approvalReleaseComponentKind {
			requiredCapabilities = append(requiredCapabilities,
				approvalv1.ExecuteCapabilityName,
				approvalv1.ReadCapabilityName,
			)
			break
		}
	}
	slices.Sort(requiredCapabilities)
	providedCapabilities := []appauthority.ProvidedCapability{
		{
			CapabilityID: "io.example.app.command.v1",
			Kind:         appauthority.CapabilityKindServiceHandler,
			HandlerRef:   "io.example.app.handler.command.v1",
			RequiredRuntimeCapabilities: []string{
				commandv1.CapabilityName,
			},
		},
		{
			CapabilityID: "io.example.app.report.v1",
			Kind:         appauthority.CapabilityKindServiceHandler,
			HandlerRef:   "io.example.app.handler.report.v1",
			RequiredRuntimeCapabilities: []string{
				reportv1.CapabilityName,
			},
		},
	}
	if slices.Contains(requiredCapabilities, approvalv1.ExecuteCapabilityName) {
		providedCapabilities = append(providedCapabilities,
			appauthority.ProvidedCapability{
				CapabilityID: "io.example.app.approval-execute.v1",
				Kind:         appauthority.CapabilityKindServiceHandler,
				HandlerRef:   "io.example.app.handler.approval-execute.v1",
				RequiredRuntimeCapabilities: []string{
					approvalv1.ExecuteCapabilityName,
				},
			},
			appauthority.ProvidedCapability{
				CapabilityID: "io.example.app.approval-read.v1",
				Kind:         appauthority.CapabilityKindServiceHandler,
				HandlerRef:   "io.example.app.handler.approval-read.v1",
				RequiredRuntimeCapabilities: []string{
					approvalv1.ReadCapabilityName,
				},
			},
		)
		slices.SortFunc(providedCapabilities, func(left, right appauthority.ProvidedCapability) int {
			return strings.Compare(left.CapabilityID, right.CapabilityID)
		})
	}
	manifest := appauthority.AppManifest{
		SchemaVersion: appauthority.AppManifestSchemaVersion,
		AppID:         "io.example.app", PublisherID: "io.example",
		SemanticVersion: "1.0.0", MetadataBundleDigest: "sha256:" + strings.Repeat("0", 64),
		Dependencies: []appauthority.Dependency{}, OwnedNamespaces: []string{"io.example.app"},
		RequiredProtocols: []appauthority.ProtocolRequirement{{
			ProtocolID: "nexuscrm.runtime.v1", Major: 1,
		}},
		RequiredEngineCapabilities: requiredCapabilities,
		ProvidedCapabilities:       providedCapabilities,
		FrontendCompatibility: appauthority.FrontendCompatibility{
			Mode: appauthority.FrontendModeNone,
		},
	}
	digest, err := appauthority.MetadataBundleDigest(bundle, manifest)
	if err != nil {
		t.Fatal(err)
	}
	manifest.MetadataBundleDigest = digest
	verified, err := appauthority.VerifyPackage(appauthority.Package{
		Manifest: manifest, Bundle: bundle, ComponentBlobs: blobs,
	})
	if err != nil {
		data, _ := json.Marshal(manifest)
		t.Fatalf("verify platform release (%s): %v", data, err)
	}
	return verified
}

func approvalReleaseBehavior(t *testing.T, objectAPIName, developerName string) []byte {
	t.Helper()
	order := 1
	definition := &approvalir.Definition{
		Label: "Primary review", Active: true, ProcessOrder: &order,
		Policy: approvalir.ApprovalPolicy{
			RecordEditability: approvalir.RecordEditabilityAdminOnly,
			AllowedSubmitters: []approvalir.AllowedSubmitter{{
				Kind: approvalir.SubmitterKindAllInternalUsers,
			}},
		},
		Steps: []approvalir.Step{{
			Name: "Review", Label: "Review",
			Approvers:       []approvalir.Approver{{Kind: approvalir.ApproverKindUser, Reference: "user-1"}},
			RejectBehavior:  approvalir.RejectBehaviorFinalRejection,
			ApprovalActions: []approvalir.Action{}, RejectionActions: []approvalir.Action{},
		}},
		InitialSubmissionActions: []approvalir.Action{}, StepApprovalActions: []approvalir.Action{},
		FinalApprovalActions: []approvalir.Action{{
			Name: "Run follow-up", Kind: approvalir.ActionKindFlow,
			Flow: &approvalir.FlowAction{APIName: "ApprovalOnlyFlow"},
		}}, FinalRejectionActions: []approvalir.Action{},
		RecallActions: []approvalir.Action{}, ReassignActions: []approvalir.Action{},
	}
	envelope, err := approvalir.EncodeDefinitionEnvelope([]byte("product-owned approval source"), definition, nil)
	if err != nil {
		t.Fatal(err)
	}
	behavior, err := json.Marshal(approvalReleaseDocument{
		ObjectAPIName: objectAPIName, DeveloperName: developerName,
		DefinitionEnvelope: envelope,
	})
	if err != nil {
		t.Fatal(err)
	}
	return behavior
}

func TestProjectionProfileClosesM1PlatformCapabilitySet(t *testing.T) {
	for _, capability := range []string{
		consumerv1.AppMetadataCapabilityName,
		consumerv1.AppMetadataV2CapabilityName,
		consumerv1.IntegrationBindingCapabilityName,
		effectivepermissionsv1.CapabilityName,
		searchv1.CapabilityName,
		reportv1.CapabilityName,
		filesv1.CapabilityName,
		commandv1.CapabilityName,
		flowv1.CapabilityName,
		approvalv1.ExecuteCapabilityName,
		approvalv1.ReadCapabilityName,
		auditlogv1.CapabilityName,
	} {
		t.Run(capability, func(t *testing.T) {
			if _, err := projectionProfile(capability); err != nil {
				t.Fatalf("M1 capability has no Catalog projection: %v", err)
			}
		})
	}
}
