package controlplane

import (
	"os"
	"strings"
	"testing"
)

func TestControlPlaneGroupMembershipClosureRebuildsUseLock(t *testing.T) {
	source, err := os.ReadFile("operations.go")
	if err != nil {
		t.Fatalf("read operations.go: %v", err)
	}
	text := string(source)

	if strings.Contains(text, "infraPersistence.RebuildGroupMembershipClosure(ctx,") {
		t.Fatal("control-plane group membership closure rebuilds must use RebuildGroupMembershipClosureWithLock")
	}
	if !strings.Contains(text, "infraPersistence.RebuildGroupMembershipClosureWithLock(ctx,") {
		t.Fatal("control-plane operations do not call RebuildGroupMembershipClosureWithLock")
	}
}

func TestRunRepairLookupReferenceBackfillIsFatalAfterMetadataReconciliation(t *testing.T) {
	source, err := os.ReadFile("operations.go")
	if err != nil {
		t.Fatalf("read operations.go: %v", err)
	}
	text := string(source)

	lookupCall := `trackStepFatal("BackfillLookupReferences"`
	if !strings.Contains(text, lookupCall) {
		t.Fatal("BackfillLookupReferences must be run through trackStepFatal so unresolved live ReferenceTo drift aborts RunRepair")
	}
	if strings.Contains(text, `trackStep("BackfillLookupReferences"`) {
		t.Fatal("BackfillLookupReferences must not use best-effort trackStep; that records errors but lets RunRepair return success")
	}

	normalize := strings.Index(text, `trackStep("NormalizeObjectIds"`)
	reconcile := strings.Index(text, `trackStep("ReconcileOrphanFieldObjectIds"`)
	lookup := strings.Index(text, lookupCall)
	if normalize == -1 || reconcile == -1 || lookup == -1 {
		t.Fatalf("missing repair step markers: NormalizeObjectIds=%d ReconcileOrphanFieldObjectIds=%d BackfillLookupReferences=%d", normalize, reconcile, lookup)
	}
	if !(normalize < reconcile && reconcile < lookup) {
		t.Fatalf("BackfillLookupReferences must run after object-id normalization and orphan-field reconciliation; got NormalizeObjectIds=%d ReconcileOrphanFieldObjectIds=%d BackfillLookupReferences=%d", normalize, reconcile, lookup)
	}
}

func TestRunRepairWiresCompatibilityBackfillsAfterMetadataConvergence(t *testing.T) {
	source, err := os.ReadFile("operations.go")
	if err != nil {
		t.Fatalf("read operations.go: %v", err)
	}
	text := string(source)

	markers := map[string]int{
		"BackfillLookupReferences":                strings.Index(text, `trackStepFatal("BackfillLookupReferences"`),
		"MigrateIsPolymorphicMultiTargetBackfill": strings.Index(text, `trackStepFatal("MigrateIsPolymorphicMultiTargetBackfill"`),
		"MigrateMasterDetailRequiredBackfill":     strings.Index(text, `trackStepFatal("MigrateMasterDetailRequiredBackfill"`),
		"MigrateMultiPicklistStorageBackfill":     strings.Index(text, `trackStep("MigrateMultiPicklistStorageBackfill"`),
		"MigrateMultiPicklistWrapperRepair":       strings.Index(text, `trackStep("MigrateMultiPicklistWrapperRepair"`),
		"BackfillContentCompatSystemFiles":        strings.Index(text, `trackStep("BackfillContentCompatSystemFiles"`),
		"ReconcileFlowOrphans":                    strings.Index(text, `trackStepFatal("ReconcileFlowOrphans"`),
	}
	for name, idx := range markers {
		if idx < 0 {
			t.Fatalf("RunRepair missing %s marker", name)
		}
	}
	if strings.Contains(text, `trackStepFatal("MigrateMultiPicklistStorageBackfill"`) ||
		strings.Contains(text, `trackStepFatal("MigrateMultiPicklistWrapperRepair"`) ||
		strings.Contains(text, `trackStepFatal("BackfillContentCompatSystemFiles"`) {
		t.Fatal("compatibility storage/content backfills must remain observable best-effort repair steps")
	}

	if !(markers["BackfillLookupReferences"] < markers["MigrateIsPolymorphicMultiTargetBackfill"] &&
		markers["MigrateIsPolymorphicMultiTargetBackfill"] < markers["MigrateMasterDetailRequiredBackfill"] &&
		markers["MigrateMasterDetailRequiredBackfill"] < markers["MigrateMultiPicklistStorageBackfill"] &&
		markers["MigrateMultiPicklistStorageBackfill"] < markers["MigrateMultiPicklistWrapperRepair"] &&
		markers["MigrateMultiPicklistWrapperRepair"] < markers["BackfillContentCompatSystemFiles"] &&
		markers["BackfillContentCompatSystemFiles"] < markers["ReconcileFlowOrphans"]) {
		t.Fatalf("compatibility backfills must run after metadata convergence and before flow repair; markers=%v", markers)
	}
}

func TestRunL0RepairDoesNotStampGlobalFieldMetadataMigrations(t *testing.T) {
	runL0Repair := parseControlplaneFuncDecl(t, "operations.go", "RunL0Repair")

	if findFuncCallByName(runL0Repair, "MigrateIsPolymorphicMultiTargetBackfill") != nil {
		t.Fatal("RunL0Repair must not stamp the global polymorphic metadata migration before broad ReferenceTo repair")
	}
	if findFuncCallByName(runL0Repair, "MigrateMasterDetailRequiredBackfill") != nil {
		t.Fatal("RunL0Repair must not stamp the global master-detail metadata migration before broad metadata repair")
	}
	if findFuncCallByName(runL0Repair, "BackfillPolymorphicDiscriminators") == nil {
		t.Fatal("RunL0Repair must retain the managed-L0 discriminator data repair")
	}
}
