package packs

import "sort"

type InstallPlanPhase string

const (
	InstallPlanPhaseObjectMetadata InstallPlanPhase = "object_metadata"
	InstallPlanPhaseSecurity       InstallPlanPhase = "security"
	InstallPlanPhaseRules          InstallPlanPhase = "rules"
	InstallPlanPhaseAutomationPrep InstallPlanPhase = "automation_prerequisites"
	InstallPlanPhaseAutomation     InstallPlanPhase = "automation"
	InstallPlanPhaseUISurfaces     InstallPlanPhase = "ui_surfaces"
	InstallPlanPhaseReporting      InstallPlanPhase = "reporting"
)

type ComponentWriteSurface struct {
	Table string
	Fact  string
}

type ComponentKindContract struct {
	Kind               ComponentKind
	Phase              InstallPlanPhase
	WriteSet           []ComponentWriteSurface
	BusinessKey        string
	OwnerDiscriminator ComponentOwnerStrategy
	Manageabilities    map[Manageability]struct{}
	VerifyProjection   string
	CollisionKey       string

	sourceBuildHandler      sourceBackedComponentBuildHandler
	sourceConnectorIdentity sourceBackedConnectorIdentityExtractor
}

func DefaultComponentKindContracts() map[ComponentKind]ComponentKindContract {
	contracts := defaultComponentKindContracts()
	attachSourceBackedComponentBuildHandlers(contracts)
	attachSourceBackedConnectorIdentityExtractors(contracts)
	return contracts
}

func defaultComponentKindContracts() map[ComponentKind]ComponentKindContract {
	return map[ComponentKind]ComponentKindContract{
		ComponentKindObjectSpec: {
			Kind:  ComponentKindObjectSpec,
			Phase: InstallPlanPhaseObjectMetadata,
			WriteSet: []ComponentWriteSurface{
				{Table: "_System_Table", Fact: "table declaration"},
				{Table: "_System_Object", Fact: "object declaration"},
				{Table: "_System_Field", Fact: "field declaration"},
				{Table: "<object table>", Fact: "physical object storage"},
			},
			BusinessKey:        "manifest component businessKey",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			// Both tiers are supported: `locked` keeps schema/sharingModel as a
			// final L1 product contract; `defaults_only` ships the same payload
			// as L1 defaults that admins can override at L2 (e.g. OWD changes
			// recorded with IsCustomized=1, mapped to specdrift's
			// CustomizationPolicyAllow). See pack_component.go enum doc and
			// source_backed_pack.go's specdriftPolicyForManageability.
			Manageabilities:  manageabilitySet(ManageabilityLocked, ManageabilityDefaultsOnly),
			VerifyProjection: "owner-scoped object metadata plus physical schema",
			CollisionKey:     "object api name",
		},
		ComponentKindObjectRecordMutationPolicy: {
			Kind:               ComponentKindObjectRecordMutationPolicy,
			Phase:              InstallPlanPhaseObjectMetadata,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_Object", Fact: "access policy recordMutation overlay"}},
			BusinessKey:        "object api name",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			// This component owns only AccessPolicy.recordMutation. Other
			// AccessPolicy sub-facts remain owned by object_spec or future
			// dedicated sub-fact surfaces; apply must merge instead of replacing
			// the whole AccessPolicy blob.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "object metadata recordMutation access policy projection",
			CollisionKey:     "object api name",
		},
		ComponentKindObjectLifecyclePolicy: {
			Kind:               ComponentKindObjectLifecyclePolicy,
			Phase:              InstallPlanPhaseObjectMetadata,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_Object", Fact: "access policy lifecycle overlay"}},
			BusinessKey:        "object api name",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			// This component owns only AccessPolicy.lifecycle. Other
			// AccessPolicy sub-facts remain owned by object_spec or sibling
			// dedicated sub-fact surfaces; apply must merge instead of
			// replacing the whole AccessPolicy blob.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "object metadata lifecycle access policy projection",
			CollisionKey:     "object api name",
		},
		ComponentKindRecordType: {
			Kind:               ComponentKindRecordType,
			Phase:              InstallPlanPhaseObjectMetadata,
			WriteSet:           []ComponentWriteSurface{{Table: "RecordType", Fact: "record type and optional code"}},
			BusinessKey:        "object api name / record type name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "owner-scoped active record type rows",
			CollisionKey:       "object api name / record type name",
		},
		ComponentKindRecordTypePicklistValue: {
			Kind:               ComponentKindRecordTypePicklistValue,
			Phase:              InstallPlanPhaseObjectMetadata,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_RecordTypePicklistValue", Fact: "record-type-scoped picklist values"}},
			BusinessKey:        "object api name / record type name / field api name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "owner-scoped record-type picklist value rows preserving customized overlays",
			CollisionKey:       "record type id / field id / value",
		},
		ComponentKindListFields: {
			Kind:               ComponentKindListFields,
			Phase:              InstallPlanPhaseObjectMetadata,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_Object", Fact: "default list fields"}},
			BusinessKey:        "object api name",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "object metadata list field projection",
			CollisionKey:       "object api name",
		},
		ComponentKindAutoNumberFormat: {
			Kind:               ComponentKindAutoNumberFormat,
			Phase:              InstallPlanPhaseObjectMetadata,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_AutoNumberFormat", Fact: "auto-number format"}},
			BusinessKey:        "object api name / field api name",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "auto-number metadata projection",
			CollisionKey:       "object api name / field api name",
		},
		ComponentKindCustomField: {
			Kind:               ComponentKindCustomField,
			Phase:              InstallPlanPhaseObjectMetadata,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_Field", Fact: "field declaration"}},
			BusinessKey:        "object api name / field api name",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "declared custom field extension reference",
			CollisionKey:       "object api name / field api name",
		},
		ComponentKindPermission: {
			Kind:               ComponentKindPermission,
			Phase:              InstallPlanPhaseSecurity,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_Permission", Fact: "permission metadata"}},
			BusinessKey:        "permission api name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "owner-scoped permission metadata",
			CollisionKey:       "permission api name",
		},
		ComponentKindSystemPermissionGrants: {
			Kind:  ComponentKindSystemPermissionGrants,
			Phase: InstallPlanPhaseSecurity,
			WriteSet: []ComponentWriteSurface{
				{Table: "_System_PermissionSetPermission", Fact: "profile-owned system permission grant"},
			},
			BusinessKey:        "permission api name",
			OwnerDiscriminator: ComponentOwnerStrategyRuntimeDataExcluded,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "permission catalog presence plus profile-owned PermissionSet junction rows",
			CollisionKey:       "permission api name / profile name / permission set target",
		},
		ComponentKindValidationRule: {
			Kind:               ComponentKindValidationRule,
			Phase:              InstallPlanPhaseRules,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_ValidationRule", Fact: "validation rule"}},
			BusinessKey:        "object api name / validation rule name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "owner-scoped validation rule rows preserving customized overlays",
			CollisionKey:       "object api name / validation rule name",
		},
		ComponentKindFieldMapping: {
			Kind:               ComponentKindFieldMapping,
			Phase:              InstallPlanPhaseRules,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_ObjectFieldMapping", Fact: "field mapping"}},
			BusinessKey:        "source object / target object / action type",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "owner-scoped field mapping rows with tenant override precedence",
			CollisionKey:       "source object / target object / action type",
		},
		ComponentKindFormulaFunctionBundle: {
			Kind:               ComponentKindFormulaFunctionBundle,
			Phase:              InstallPlanPhaseRules,
			WriteSet:           []ComponentWriteSurface{{Table: "process-local formula function registry", Fact: "formula function bundle"}},
			BusinessKey:        "pack-level business key",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "pack-authored formula function bundle declaration",
			CollisionKey:       "function name",
		},
		ComponentKindAutoNumberCounter: {
			Kind:               ComponentKindAutoNumberCounter,
			Phase:              InstallPlanPhaseRules,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_AutoNumberCounter", Fact: "counter seed"}},
			BusinessKey:        "object api name / field api name / scope",
			OwnerDiscriminator: ComponentOwnerStrategyRuntimeDataExcluded,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "runtime counter seed preflight",
			CollisionKey:       "object api name / field api name / scope",
		},
		ComponentKindStandardFlow: {
			Kind:               ComponentKindStandardFlow,
			Phase:              InstallPlanPhaseAutomation,
			WriteSet:           []ComponentWriteSurface{{Table: "FlowDefinition", Fact: "flow definition"}, {Table: "Flow", Fact: "flow version"}},
			BusinessKey:        "flow developer name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "owner-scoped flow definition and active standard version",
			CollisionKey:       "flow developer name",
		},
		ComponentKindEmailTemplate: {
			Kind:               ComponentKindEmailTemplate,
			Phase:              InstallPlanPhaseAutomationPrep,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_EmailTemplate", Fact: "native email template content"}},
			BusinessKey:        "email template developer name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "owner-scoped native email template row",
			CollisionKey:       "owner pack / developer name",
		},
		ComponentKindInvocableAction: {
			Kind:               ComponentKindInvocableAction,
			Phase:              InstallPlanPhaseAutomation,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_StandardAction", Fact: "invocable action"}},
			BusinessKey:        "action api name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "owner-scoped invocable action metadata",
			CollisionKey:       "action api name",
		},
		ComponentKindFlowActionCallHandler: {
			Kind:               ComponentKindFlowActionCallHandler,
			Phase:              InstallPlanPhaseAutomation,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_FlowActionCallHandler", Fact: "Flow actionCall handler declaration"}},
			BusinessKey:        "normalized action type",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "global Flow actionCall handler declaration with owner attribution",
			CollisionKey:       "normalized action type",
		},
		ComponentKindRelatedListRule: {
			Kind:               ComponentKindRelatedListRule,
			Phase:              InstallPlanPhaseUISurfaces,
			WriteSet:           []ComponentWriteSurface{{Table: "process-local related-list registry", Fact: "related-list rule"}},
			BusinessKey:        "object api name / related object api name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "pack related-list rule declaration",
			CollisionKey:       "object api name / related object api name",
		},
		ComponentKindPageLayout: {
			Kind:               ComponentKindPageLayout,
			Phase:              InstallPlanPhaseUISurfaces,
			WriteSet:           []ComponentWriteSurface{{Table: "PageLayout", Fact: "page layout"}, {Table: "LayoutAssignment", Fact: "layout assignment"}},
			BusinessKey:        "object api name / layout name",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "layout plus assignment projection",
			CollisionKey:       "object api name / layout name",
		},
		ComponentKindLayoutAssignment: {
			Kind:               ComponentKindLayoutAssignment,
			Phase:              InstallPlanPhaseUISurfaces,
			WriteSet:           []ComponentWriteSurface{{Table: "LayoutAssignment", Fact: "record-type-scoped layout routing"}},
			BusinessKey:        "manifest component businessKey",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "owner-scoped record-type layout assignment routing",
			CollisionKey:       "object api name / record type name",
		},
		ComponentKindUIAction: {
			Kind:               ComponentKindUIAction,
			Phase:              InstallPlanPhaseUISurfaces,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_Action", Fact: "ui action"}},
			BusinessKey:        "action api name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "owner-scoped UI action metadata",
			CollisionKey:       "action api name",
		},
		ComponentKindReportType: {
			Kind:               ComponentKindReportType,
			Phase:              InstallPlanPhaseReporting,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_ReportType", Fact: "report type"}},
			BusinessKey:        "report type full name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "owner-scoped report type projection including sections/categories/join/metadata",
			CollisionKey:       "report type full name",
		},
		ComponentKindChildCloneRules: {
			Kind:               ComponentKindChildCloneRules,
			Phase:              InstallPlanPhaseRules,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_Object", Fact: "child-clone rules"}},
			BusinessKey:        "object api name",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			// The source-backed child_clone_rules component is a manifest
			// partition that overlays the owning object_spec payload. The
			// _System_Object.ChildCloneRules live column and ChildCloneRulesPack*
			// sidecars remain owned and verified by object_spec, whose
			// manageability controls L2 override behavior.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "owner-scoped child-clone rules per object",
			CollisionKey:     "object api name",
		},
		ComponentKindSearchScopeOrder: {
			Kind:               ComponentKindSearchScopeOrder,
			Phase:              InstallPlanPhaseUISurfaces,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_InstalledPack", Fact: "search scope order"}},
			BusinessKey:        "pack-level business key",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			Manageabilities:    manageabilitySet(ManageabilityDefaultsOnly),
			VerifyProjection:   "search scope order items from pack payload",
			CollisionKey:       "pack name / business key",
		},
		ComponentKindSearchAllDefaultFields: {
			Kind:               ComponentKindSearchAllDefaultFields,
			Phase:              InstallPlanPhaseUISurfaces,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_InstalledPack", Fact: "search all default fields"}},
			BusinessKey:        "pack-level business key",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "per-object SOSL ALL default search fields from pack payload",
			CollisionKey:       "pack name / business key",
		},
		ComponentKindHrefRewriteFields: {
			Kind:               ComponentKindHrefRewriteFields,
			Phase:              InstallPlanPhaseUISurfaces,
			WriteSet:           []ComponentWriteSurface{{Table: "process-local href rewrite registry", Fact: "record-read href rewrite field declaration"}},
			BusinessKey:        "pack-level business key",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "href rewrite field declarations from pack payload",
			CollisionKey:       "parent object api name / field api name",
		},
		ComponentKindFolderType: {
			Kind:               ComponentKindFolderType,
			Phase:              InstallPlanPhaseReporting,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_FolderType", Fact: "folder type permission binding"}},
			BusinessKey:        "pack-level folder type catalog",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "owner-scoped active folder type rows",
			CollisionKey:       "folder type api name",
		},
		ComponentKindOAuthCustomScope: {
			Kind:               ComponentKindOAuthCustomScope,
			Phase:              InstallPlanPhaseSecurity,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_OAuthCustomScope", Fact: "OAuth custom scope route policy"}},
			BusinessKey:        "scope name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerlessManifest,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "scope policy row keyed by scope name",
			CollisionKey:       "scope name",
		},
		ComponentKindConnectedApp: {
			Kind:               ComponentKindConnectedApp,
			Phase:              InstallPlanPhaseSecurity,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_ConnectedApp", Fact: "OAuth Connected App policy"}},
			BusinessKey:        "connected app id",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerlessManifest,
			Manageabilities:    manageabilitySet(ManageabilityLocked),
			VerifyProjection:   "Connected App policy row keyed by id, including runtime-read security fields",
			CollisionKey:       "connected app id",
		},
		ComponentKindWebhookSecret: {
			Kind:  ComponentKindWebhookSecret,
			Phase: InstallPlanPhaseSecurity,
			WriteSet: []ComponentWriteSurface{
				{Table: "_System_WebhookSecret", Fact: "webhook secret definition"},
			},
			BusinessKey:        "owner pack / name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			// Algorithm + name are L1 product facts declared by the connector pack;
			// admins cannot customize them. Locked enforces that the pack is the
			// sole authority on the definition shape.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "owner-scoped webhook secret definition rows",
			CollisionKey:     "owner pack / name",
		},
		ComponentKindConnectorCapability: {
			Kind:               ComponentKindConnectorCapability,
			Phase:              InstallPlanPhaseObjectMetadata,
			WriteSet:           []ComponentWriteSurface{{Table: "_System_ConnectorCapabilityDeclaration", Fact: "connector capability binding"}},
			BusinessKey:        "namespace:kind",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			// locked: capability bindings are part of the pack's signed contract;
			// admins must not be able to override which capabilities a connector
			// pack declares — that would break the connector SDK RFC invariant.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "connector capability declaration row (namespace, kind, payloadHash)",
			CollisionKey:     "namespace / kind",
		},
		ComponentKindConnectorRateLimit: {
			Kind:  ComponentKindConnectorRateLimit,
			Phase: InstallPlanPhaseRules,
			WriteSet: []ComponentWriteSurface{
				{Table: "_System_ConnectorRateLimit", Fact: "connector rate-limit policy"},
			},
			BusinessKey:        "owner pack / endpoint class",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			// Rate-limit policy (rps, burst) is an L1 product fact declared by the
			// connector pack. Admins cannot override limits in v1; Locked enforces
			// that the pack is the sole authoring surface (NCRM-INT-04B).
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "owner-scoped rate-limit policy rows",
			CollisionKey:     "owner pack / endpoint class",
		},
		ComponentKindConnectorInboundHandlerConfig: {
			Kind:  ComponentKindConnectorInboundHandlerConfig,
			Phase: InstallPlanPhaseObjectMetadata,
			WriteSet: []ComponentWriteSurface{
				{Table: "_System_ConnectorInboundHandlerConfig", Fact: "connector inbound handler config"},
			},
			BusinessKey:        "namespace:capabilityKind",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			// Handler configs are L1 connector-pack facts. Admins cannot override
			// them in v1 because stale signature/envelope config changes runtime
			// trust boundaries; Locked keeps the pack payload authoritative.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "pack-incarnation connector inbound handler config row",
			CollisionKey:     "namespace / capability kind",
		},
		ComponentKindConnectorInboundRoute: {
			Kind:  ComponentKindConnectorInboundRoute,
			Phase: InstallPlanPhaseAutomation,
			WriteSet: []ComponentWriteSurface{
				{Table: "_System_ConnectorInboundRoute", Fact: "connector inbound route declaration"},
			},
			// BusinessKey is packName/namespace; one component per namespace per pack.
			// Individual routes within the component are addressed by the
			// (InstalledPackId, EventKind) UNIQUE index.
			BusinessKey:        "pack name / namespace",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			// Routing declarations are L1 product facts owned by the connector pack;
			// admins cannot override which event kinds a pack routes — that would
			// silently re-route events to unintended flows. Locked enforces the
			// pack is the sole authoring surface.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "owner-scoped connector inbound route rows (namespace, eventKind, flowDeveloperName)",
			CollisionKey:     "pack name / namespace",
		},
		ComponentKindConnectorCalloutProfile: {
			Kind:  ComponentKindConnectorCalloutProfile,
			Phase: InstallPlanPhaseRules,
			WriteSet: []ComponentWriteSurface{
				{Table: "_System_ConnectorCalloutProfile", Fact: "connector callout profile"},
			},
			BusinessKey:        "owner pack / profile name",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			// Callout profiles (retry policy, pagination, batch spec) are L1 product
			// facts declared by the connector pack. Locked enforces that the pack is
			// the sole authoring surface (NCRM-INT-10).
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "owner-scoped callout profile rows",
			CollisionKey:     "owner pack / profile name",
		},
		ComponentKindConnectorFieldMapping: {
			Kind:  ComponentKindConnectorFieldMapping,
			Phase: InstallPlanPhaseRules,
			WriteSet: []ComponentWriteSurface{
				{Table: "_System_ObjectFieldMapping", Fact: "connector field mapping"},
			},
			// Business key includes direction so inbound and outbound rows for the
			// same (source, sourceObject, targetObject, actionType, sourceField) tuple
			// are treated as distinct entries and cannot silently overwrite each other.
			BusinessKey:        "source / source object / target object / action type / source field / direction",
			OwnerDiscriminator: ComponentOwnerStrategySource,
			// Locked: connector field mapping rows are pack-managed data-flow
			// metadata authored by the declaring companion app-pack. Connector
			// identity remains in ConnectorPack and is linked by PackDependency;
			// admins cannot customise mapping rows at L2 (the writer hardcodes
			// IsCustomized=0). RFC #1547 defers optional admin overlay.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "owner-scoped connector field mapping rows with direction",
			CollisionKey:     "source / source object / target object / action type / source field / direction",
		},
		ComponentKindConnectorPushContract: {
			Kind:  ComponentKindConnectorPushContract,
			Phase: InstallPlanPhaseRules,
			WriteSet: []ComponentWriteSurface{
				{Table: "source-backed pack manifest", Fact: "connector push durable metadata contract"},
			},
			BusinessKey:        "owner pack / flow developer name / flow action name / stable slot lineage / source object / destination slot",
			OwnerDiscriminator: ComponentOwnerStrategyOwnerPack,
			// Locked: durable PushToConnector identity and write-target metadata are
			// L1 app-pack facts. Admin/runtime values may supply the source record
			// id and outbound payload, but must not redefine connectorOwnerKey,
			// slotLineageId/actionSlotId, destinationSlotId, paths, or writeback fields.
			Manageabilities:  manageabilitySet(ManageabilityLocked),
			VerifyProjection: "pack-owned literal durable identity/write-target assembly",
			CollisionKey:     "owner pack / stable slot lineage / source object / destination slot",
		},
	}
}

type sourceBackedConnectorIdentityRole string

const (
	sourceBackedConnectorIdentityWebhookSecret        sourceBackedConnectorIdentityRole = "webhook_secret"
	sourceBackedConnectorIdentityCapability           sourceBackedConnectorIdentityRole = "connector_capability"
	sourceBackedConnectorIdentityInboundHandlerConfig sourceBackedConnectorIdentityRole = "connector_inbound_handler_config"
)

type sourceBackedConnectorComponentIdentity struct {
	Role           sourceBackedConnectorIdentityRole
	Namespace      string
	CapabilityKind string
	WebhookSecret  string
	Config         []byte
}

type sourceBackedConnectorIdentityExtractor func([]byte) (sourceBackedConnectorComponentIdentity, bool)

func DefaultInstallPlanPhaseOrder() []InstallPlanPhase {
	return []InstallPlanPhase{
		InstallPlanPhaseObjectMetadata,
		InstallPlanPhaseSecurity,
		InstallPlanPhaseRules,
		InstallPlanPhaseAutomationPrep,
		InstallPlanPhaseAutomation,
		InstallPlanPhaseUISurfaces,
		InstallPlanPhaseReporting,
	}
}

func InstallPlanPhaseRank(phase InstallPlanPhase) (int, bool) {
	for i, candidate := range DefaultInstallPlanPhaseOrder() {
		if candidate == phase {
			return i, true
		}
	}
	return 0, false
}

func ComponentKindContractFor(kind ComponentKind) (ComponentKindContract, bool) {
	contract, ok := DefaultComponentKindContracts()[kind]
	return contract, ok
}

func manageabilitySet(values ...Manageability) map[Manageability]struct{} {
	out := make(map[Manageability]struct{}, len(values))
	for _, value := range values {
		out[value] = struct{}{}
	}
	return out
}

func sortedContractKinds(contracts map[ComponentKind]ComponentKindContract) []ComponentKind {
	kinds := make([]ComponentKind, 0, len(contracts))
	for kind := range contracts {
		kinds = append(kinds, kind)
	}
	sort.Slice(kinds, func(i, j int) bool {
		return kinds[i] < kinds[j]
	})
	return kinds
}
