//go:build integration

package controlplane

import (
	"context"
	"database/sql"
	"strings"
	"testing"
	"time"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

func TestSourcePackOwnershipPreflightOutcomesOnTiDB(t *testing.T) {
	cfg, cleanup := newTemporaryIntegrationDatabase(t)
	t.Cleanup(cleanup)

	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
	t.Cleanup(cancel)
	conn := initializeControlPlaneMetadata(t, ctx, cfg)
	t.Cleanup(func() { _ = conn.Close() })
	db := conn.DB()

	t.Run("owner surfaces use live catalog ownership", func(t *testing.T) {
		if err := validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil); err != nil {
			t.Fatalf("clean canonical catalog: %v", err)
		}

		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_Field
			(Id, ObjectId, ApiName, Label, Type, OwnerKind, OwnerPack, IsDeleted, CreatedDate, LastModifiedDate)
			SELECT 'ownership-field', Id, 'OwnershipMarker__c', 'Ownership Marker', 'string', 'pack', 'other-pack', 0, NOW(), NOW()
			FROM _System_Object WHERE ApiName = 'User' LIMIT 1`)
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_Field WHERE Id = 'ownership-field'`)
		})

		assertOwnershipPreflightError(t,
			validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil),
			"_System_Field rows owned by non-active pack", "other-pack:User/OwnershipMarker__c")

		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Field SET OwnerPack = 'active-pack' WHERE Id = 'ownership-field'`)
		if err := validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil); err != nil {
			t.Fatalf("active field owner: %v", err)
		}

		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Field SET OwnerKind = 'pack_removing' WHERE Id = 'ownership-field'`)
		assertOwnershipPreflightError(t,
			validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil),
			"_System_Field pack_removing rows owned by non-removing pack")
		if err := validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, []string{"active-pack"}, nil); err != nil {
			t.Fatalf("declared removal window: %v", err)
		}

		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Field SET OwnerKind = 'pack', OwnerPack = '' WHERE Id = 'ownership-field'`)
		assertOwnershipPreflightError(t,
			validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil),
			"_System_Field rows owned by non-active pack", ":User/OwnershipMarker__c")

		mustExecOwnershipPreflight(t, ctx, db, `DELETE FROM _System_Field WHERE Id = 'ownership-field'`)
		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_ConnectorRateLimit
			(Id, OwnerPack, EndpointClass, RequestsPerSecond, Burst, Description, IsDeleted, CreatedDate, LastModifiedDate)
			VALUES ('ownership-rate-limit', 'other-pack', 'ownership-endpoint', 5, 10, '', 0, NOW(), NOW())`)
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_ConnectorRateLimit WHERE Id = 'ownership-rate-limit'`)
		})
		assertOwnershipPreflightError(t,
			validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil),
			"_System_ConnectorRateLimit rows owned by non-active pack", "other-pack:ownership-endpoint")
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_ConnectorRateLimit SET OwnerPack = 'active-pack' WHERE Id = 'ownership-rate-limit'`)
		if err := validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil); err != nil {
			t.Fatalf("active connector rate-limit owner: %v", err)
		}

		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_ConnectorCalloutProfile
			(Id, InstalledPackId, OwnerPack, ProfileName, CredentialRef, EndpointClass, RetryPolicy, PageSpec, BatchSpec, ObjectPathMap, Description, IsDeleted, CreatedDate, LastModifiedDate)
			VALUES ('ownership-callout-profile', 'ownership-install', 'other-pack', 'ownership-profile', 'ownership-credential',
				'ownership-endpoint', '{}', '{}', '{}', '{}', '', 0, NOW(), NOW())`)
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_ConnectorCalloutProfile WHERE Id = 'ownership-callout-profile'`)
		})
		assertOwnershipPreflightError(t,
			validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil),
			"_System_ConnectorCalloutProfile rows owned by non-active pack", "other-pack:ownership-profile")
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_ConnectorCalloutProfile SET OwnerPack = 'active-pack' WHERE Id = 'ownership-callout-profile'`)
		if err := validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil); err != nil {
			t.Fatalf("active connector callout-profile owner: %v", err)
		}

		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Object
			SET AccessPolicyRecordMutationPackName = 'other-pack', AccessPolicyRecordMutationPackBusinessKey = ApiName
			WHERE ApiName = 'User'`)
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `UPDATE _System_Object
				SET AccessPolicyRecordMutationPackName = NULL, AccessPolicyRecordMutationPackBusinessKey = NULL
				WHERE ApiName = 'User'`)
		})
		assertOwnershipPreflightError(t,
			validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil),
			"_System_Object.AccessPolicyRecordMutation rows owned by non-active pack", "other-pack:User")
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Object SET AccessPolicyRecordMutationPackName = 'active-pack' WHERE ApiName = 'User'`)
		if err := validateInstallPackOwnerPackSurfaces(ctx, db, []string{"active-pack"}, nil, nil); err != nil {
			t.Fatalf("active generic owner surface: %v", err)
		}
	})

	t.Run("child relationship namespace uses live fields", func(t *testing.T) {
		pack := testControlplaneChildRelationshipPack(t, "relationship-pack", "Children")
		for _, statement := range []string{
			`INSERT INTO _System_Object (Id, ApiName, Label, PluralLabel, IsDeleted, CreatedDate, LastModifiedDate)
			 VALUES ('ownership-parent', 'Parent__c', 'Parent', 'Parents', 0, NOW(), NOW())`,
			`INSERT INTO _System_Object (Id, ApiName, Label, PluralLabel, IsDeleted, CreatedDate, LastModifiedDate)
			 VALUES ('ownership-child-a', 'ChildA__c', 'Child A', 'Child As', 0, NOW(), NOW())`,
			`INSERT INTO _System_Object (Id, ApiName, Label, PluralLabel, IsDeleted, CreatedDate, LastModifiedDate)
			 VALUES ('ownership-child-other', 'OtherChild__c', 'Other Child', 'Other Children', 0, NOW(), NOW())`,
		} {
			mustExecOwnershipPreflight(t, ctx, db, statement)
		}
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_Field WHERE Id LIKE 'ownership-relationship-%'`)
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_Object WHERE Id IN ('ownership-parent', 'ownership-child-a', 'ownership-child-other')`)
		})

		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_Field
			(Id, ObjectId, ApiName, Label, Type, ReferenceTo, ChildRelationshipName, OwnerKind, OwnerPack, IsDeleted, CreatedDate, LastModifiedDate)
			VALUES ('ownership-relationship-live', 'ownership-child-other', 'Parent__c', 'Parent', 'reference', '["Parent__c"]', 'Children', 'pack', 'other-pack', 0, NOW(), NOW())`)
		assertOwnershipPreflightError(t,
			validateInstallPackChildRelationshipNamespacePreflight(ctx, db, pack),
			"childRelationshipName live namespace collision", "other-pack")

		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Field
			SET ObjectId = 'ownership-child-a', OwnerPack = 'relationship-pack'
			WHERE Id = 'ownership-relationship-live'`)
		for _, ownerKind := range []string{constants.FieldOwnerKindPack, constants.FieldOwnerKindPackRetained, constants.FieldOwnerKindPackRemoving} {
			mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Field SET OwnerKind = ? WHERE Id = 'ownership-relationship-live'`, ownerKind)
			if err := validateInstallPackChildRelationshipNamespacePreflight(ctx, db, pack); err != nil {
				t.Fatalf("same-pack %s rewrite: %v", ownerKind, err)
			}
		}

		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Field SET OwnerKind = 'admin' WHERE Id = 'ownership-relationship-live'`)
		assertOwnershipPreflightError(t,
			validateInstallPackChildRelationshipNamespacePreflight(ctx, db, pack),
			"childRelationshipName live namespace collision", `pack=""`)

		mustExecOwnershipPreflight(t, ctx, db, `DELETE FROM _System_Field WHERE Id = 'ownership-relationship-live'`)
		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_Field
			(Id, ObjectId, ApiName, Label, Type, IsDeleted, CreatedDate, LastModifiedDate)
			VALUES ('ownership-relationship-parent-field', 'ownership-parent', 'Children', 'Children', 'string', 0, NOW(), NOW())`)
		assertOwnershipPreflightError(t,
			validateInstallPackChildRelationshipNamespacePreflight(ctx, db, pack),
			"childRelationshipName parent field collision", "Parent__c.Children")
	})

	t.Run("business keys use live owner and canonical identity", func(t *testing.T) {
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `UPDATE _System_Object
				SET AccessPolicyRecordMutationPackName = NULL, AccessPolicyRecordMutationPackBusinessKey = NULL
				WHERE ApiName = 'User'`)
		})
		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_PageLayout
			(Id, ObjectApiName, LayoutName, Type, IsDefault, IsDeleted, Config, Source, OwnerPack, IsCustomized, CreatedDate, LastModifiedDate)
			VALUES ('curated_User_default', 'User', 'Default Layout', 'record', 0, 0, JSON_OBJECT('sections', JSON_ARRAY()), 'curated', 'other-pack', 0, NOW(), NOW())`)
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_PageLayout WHERE Id LIKE 'ownership-layout-%' OR Id = 'curated_User_default'`)
		})

		defaultKey := []requestedPageLayoutOwnershipKey{{ObjectAPIName: "User", LayoutName: "Default Layout", IsDefault: true}}
		assertOwnershipPreflightError(t,
			validateRequestedPackBusinessKeyOwnership(ctx, db, "active-pack", nil, nil, defaultKey),
			`collides with owner pack "other-pack"`)
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_PageLayout SET OwnerPack = 'active-pack' WHERE Id = 'curated_User_default'`)
		if err := validateRequestedPackBusinessKeyOwnership(ctx, db, "active-pack", nil, nil, defaultKey); err != nil {
			t.Fatalf("same-pack canonical default layout: %v", err)
		}
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_PageLayout
			SET OwnerPack = NULL, Source = 'admin_created', IsCustomized = 1
			WHERE Id = 'curated_User_default'`)
		if err := validateRequestedPackBusinessKeyOwnership(ctx, db, "active-pack", nil, nil, defaultKey); err != nil {
			t.Fatalf("admin-owned canonical default layout: %v", err)
		}
		mustExecOwnershipPreflight(t, ctx, db, `DELETE FROM _System_PageLayout WHERE Id = 'curated_User_default'`)
		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_PageLayout
			(Id, ObjectApiName, LayoutName, Type, IsDefault, IsDeleted, Config, Source, OwnerPack, IsCustomized, CreatedDate, LastModifiedDate)
			VALUES ('ownership-layout-crosspack-default-name', 'User', 'Default Layout', 'record', 0, 0, JSON_OBJECT('sections', JSON_ARRAY()), 'curated', 'other-pack', 0, NOW(), NOW())`)
		assertOwnershipPreflightError(t,
			validateRequestedPackBusinessKeyOwnership(ctx, db, "active-pack", nil, nil, defaultKey),
			`collides with owner pack "other-pack"`)
		mustExecOwnershipPreflight(t, ctx, db, `DELETE FROM _System_PageLayout WHERE Id = 'ownership-layout-crosspack-default-name'`)

		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_PageLayout
			(Id, ObjectApiName, LayoutName, Type, IsDefault, IsDeleted, Config, Source, OwnerPack, IsCustomized, CreatedDate, LastModifiedDate)
			VALUES ('ownership-layout-nondefault', 'User', 'Operations Layout', 'record', 0, 0, JSON_OBJECT('sections', JSON_ARRAY()), 'curated', 'other-pack', 0, NOW(), NOW())`)
		nonDefaultKey := []requestedPageLayoutOwnershipKey{{ObjectAPIName: "User", LayoutName: "Operations Layout"}}
		assertOwnershipPreflightError(t,
			validateRequestedPackBusinessKeyOwnership(ctx, db, "active-pack", nil, nil, nonDefaultKey),
			`collides with owner pack "other-pack"`)
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_PageLayout SET OwnerPack = 'active-pack' WHERE Id = 'ownership-layout-nondefault'`)
		if err := validateRequestedPackBusinessKeyOwnership(ctx, db, "active-pack", nil, nil, nonDefaultKey); err != nil {
			t.Fatalf("same-pack non-default layout: %v", err)
		}

		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Object
			SET AccessPolicyRecordMutationPackName = 'other-pack', AccessPolicyRecordMutationPackBusinessKey = 'User'
			WHERE ApiName = 'User'`)
		policyKey := []requestedAccessPolicySidecarOwnershipKey{{ObjectAPIName: "User", BusinessKey: "User"}}
		assertOwnershipPreflightError(t,
			validateRequestedPackBusinessKeyOwnership(ctx, db, "active-pack", nil, nil, nil, policyKey),
			"object_record_mutation_policy User", "other-pack")
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_Object SET AccessPolicyRecordMutationPackName = 'active-pack' WHERE ApiName = 'User'`)
		if err := validateRequestedPackBusinessKeyOwnership(ctx, db, "active-pack", nil, nil, nil, policyKey); err != nil {
			t.Fatalf("same-pack access policy sidecar: %v", err)
		}
	})

	t.Run("connected app identity and declaration ownership are atomic", func(t *testing.T) {
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_ConnectedAppDeclaration WHERE Id LIKE 'ownership-declaration-%'`)
			_, _ = db.ExecContext(context.Background(), `DELETE FROM _System_ConnectedApp WHERE Id LIKE 'ownership-app-%'`)
		})
		insertApp := func(id, name, key string, active bool) {
			mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_ConnectedApp
				(Id, Name, ConsumerKey, IsActive, CreatedDate, LastModifiedDate)
				VALUES (?, ?, ?, ?, NOW(), NOW())`, id, name, key, active)
		}
		insertDeclaration := func(id, packName, appID string, deleted bool) {
			mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_ConnectedAppDeclaration
				(Id, InstalledPackName, ConnectedAppId, PayloadHash, IsDeleted)
				VALUES (?, ?, ?, 'ownership-payload', ?)`, id, packName, appID, deleted)
		}
		key := func(id, name, consumerKey string) []packs.ConnectedAppOwnershipKey {
			return []packs.ConnectedAppOwnershipKey{{ID: id, Name: name, ConsumerKey: consumerKey}}
		}

		insertApp("ownership-app-cross-pack", "Cross Pack", "cross-pack-key", true)
		insertDeclaration("ownership-declaration-cross-pack", "other-pack", "ownership-app-cross-pack", false)
		assertOwnershipPreflightError(t,
			validateRequestedConnectedAppOwnership(ctx, db, "active-pack", key("ownership-app-cross-pack", "Cross Pack", "cross-pack-key")),
			`InstalledPackName = "other-pack"`)

		insertApp("ownership-app-ownerless", "Ownerless", "ownerless-key", true)
		assertOwnershipPreflightError(t,
			validateRequestedConnectedAppOwnership(ctx, db, "active-pack", key("ownership-app-ownerless", "Ownerless", "ownerless-key")),
			"already exists without source-backed declaration")

		insertApp("ownership-app-same-pack", "Same Pack", "same-pack-key", true)
		insertDeclaration("ownership-declaration-same-pack", "active-pack", "ownership-app-same-pack", false)
		if err := validateRequestedConnectedAppOwnership(ctx, db, "active-pack", key("ownership-app-same-pack", "Same Pack", "same-pack-key")); err != nil {
			t.Fatalf("same-pack declaration: %v", err)
		}

		insertApp("ownership-app-tombstone", "Tombstone", "tombstone-key", false)
		insertDeclaration("ownership-declaration-tombstone", "active-pack", "ownership-app-tombstone", true)
		if err := validateRequestedConnectedAppOwnership(ctx, db, "active-pack", key("ownership-app-tombstone", "Tombstone", "tombstone-key")); err != nil {
			t.Fatalf("inactive same-pack tombstone: %v", err)
		}
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_ConnectedApp SET IsActive = 1 WHERE Id = 'ownership-app-tombstone'`)
		assertOwnershipPreflightError(t,
			validateRequestedConnectedAppOwnership(ctx, db, "active-pack", key("ownership-app-tombstone", "Tombstone", "tombstone-key")),
			"soft-deleted declaration", "row is active")

		insertApp("ownership-app-existing", "Shared Name", "shared-key", true)
		assertOwnershipPreflightError(t,
			validateRequestedConnectedAppOwnership(ctx, db, "active-pack", key("ownership-app-new-name", "Shared Name", "new-key")),
			`Name "Shared Name" collides`)
		assertOwnershipPreflightError(t,
			validateRequestedConnectedAppOwnership(ctx, db, "active-pack", key("ownership-app-new-key", "New Name", "shared-key")),
			`ConsumerKey "shared-key" collides`)
		insertDeclaration("ownership-declaration-existing", "active-pack", "ownership-app-existing", false)
		if err := validateRequestedConnectedAppOwnership(ctx, db, "active-pack", key("ownership-app-replacement", "Shared Name", "shared-key")); err != nil {
			t.Fatalf("same-pack identity replacement: %v", err)
		}

		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO _System_ConnectedApp
			(Id, Name, ConsumerKey, CallbackUrl, RedirectUris, Scopes, IsActive, ClientType, RequirePkce,
			 TokenEndpointAuthMethod, AllowedGrantTypes, ConsentPolicy, ConsentVersion, IssueRefreshTokens,
			 PermittedUsers, CreatedDate, LastModifiedDate)
			VALUES ('ownership-app-public', 'Public BI', 'public-bi-key', 'http://127.0.0.1:1717/callback',
			 '["http://127.0.0.1:1717/callback"]', 'external.records.read', 1, 'public', 1,
			 'none', 'authorization_code', 'trusted', 1, 0, 'AllUsers', NOW(), NOW())`)
		publicKey := []packs.ConnectedAppOwnershipKey{publicConnectedAppOwnershipKey("ownership-app-public-target", "Public BI Connected App", "public-bi-key")}
		if err := validateRequestedConnectedAppOwnership(ctx, db, "active-pack", publicKey); err != nil {
			t.Fatalf("safe ownerless public client adoption: %v", err)
		}
		mustExecOwnershipPreflight(t, ctx, db, `UPDATE _System_ConnectedApp SET Scopes = 'api' WHERE Id = 'ownership-app-public'`)
		assertOwnershipPreflightError(t,
			validateRequestedConnectedAppOwnership(ctx, db, "active-pack", publicKey),
			"not safe to adopt", "Scopes")
	})

	t.Run("managed approval registration is required only for owned app rows", func(t *testing.T) {
		mustExecOwnershipPreflight(t, ctx, db, `INSERT INTO ProcessDefinition
			(Id, Name, DeveloperName, State, TableEnumOrId, IsActive, OwnerPack, CreatedDate, LastModifiedDate)
			VALUES ('ownership-approval', 'Owned Approval', 'Owned_Approval', 'Active', 'User', 1, 'active-pack', NOW(), NOW())`)
		t.Cleanup(func() {
			_, _ = db.ExecContext(context.Background(), `DELETE FROM ProcessDefinition WHERE Id = 'ownership-approval'`)
		})
		assertOwnershipPreflightError(t,
			validatePackManagedApprovalOwnership(ctx, db, "active-pack", packs.AppPack, packs.ComponentKindRegistrationSet{}),
			"no OwnerPack-scoped managed approval_process registration covers ProcessDefinition", "ownership-approval")
		if err := validatePackManagedApprovalOwnership(ctx, db, "active-pack", packs.ConnectorPack, packs.ComponentKindRegistrationSet{}); err != nil {
			t.Fatalf("connector pack approval guard: %v", err)
		}
		if err := validatePackManagedApprovalOwnership(ctx, db, "greenfield-pack", packs.AppPack, packs.ComponentKindRegistrationSet{}); err != nil {
			t.Fatalf("ownerless app approval guard: %v", err)
		}
	})
}

func mustExecOwnershipPreflight(t *testing.T, ctx context.Context, db *sql.DB, statement string, args ...any) {
	t.Helper()
	if _, err := db.ExecContext(ctx, statement, args...); err != nil {
		t.Fatalf("ownership preflight fixture: %v\n%s", err, statement)
	}
}

func assertOwnershipPreflightError(t *testing.T, err error, fragments ...string) {
	t.Helper()
	if err == nil {
		t.Fatalf("preflight error = nil, want %q", fragments)
	}
	for _, fragment := range fragments {
		if !strings.Contains(err.Error(), fragment) {
			t.Fatalf("preflight error = %v, want %q", err, fragment)
		}
	}
}
