package metadata

import (
	"context"
	"reflect"
	"strings"
	"testing"

	"github.com/nexuscrm/kernel/pkg/ports"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestResolveLayoutReturnsCuratedFallbackWithoutRuntimeAssignment(t *testing.T) {
	repo := newResolveLayoutFallbackRepo("Case", []*models.PageLayout{{
		ID:            "curated_Case_default",
		ObjectAPIName: "Case",
		LayoutName:    "Case Layout",
		Source:        "Curated",
		Sections:      []models.PageSection{{ID: "details", Label: "Details", Fields: []string{"Subject"}}},
	}})
	service := newResolveLayoutFallbackService(repo)

	layout := service.ResolveLayout(context.Background(), "Case", nil, "", "")
	if layout == nil {
		t.Fatal("ResolveLayout returned nil, want curated fallback layout")
	}
	if layout.ID != "curated_Case_default" {
		t.Fatalf("layout ID = %q, want curated_Case_default", layout.ID)
	}
	assertNoReadPathWrites(t, repo)
}

func TestResolveLayoutSuppressesRuntimeAssignmentWhenCuratedExistsInFallbackSet(t *testing.T) {
	repo := newResolveLayoutFallbackRepo("Contact", []*models.PageLayout{
		{
			ID:                "legacy_contact_layout",
			ObjectAPIName:     "Contact",
			LayoutName:        "Legacy Contact Layout",
			Source:            "auto_generated",
			GenerationVersion: currentGenerationVersion,
			Sections:          []models.PageSection{{ID: "details", Label: "Details", Fields: []string{"Name"}}},
		},
		{
			ID:            "curated_Contact_default",
			ObjectAPIName: "Contact",
			LayoutName:    "Contact Layout",
			Source:        "curated",
			Sections:      []models.PageSection{{ID: "details", Label: "Details", Fields: []string{"Name"}}},
		},
	})
	service := newResolveLayoutFallbackService(repo)

	layout := service.ResolveLayout(context.Background(), "Contact", nil, "", "")
	if layout == nil {
		t.Fatal("ResolveLayout returned nil, want persisted fallback layout")
	}
	if layout.ID != "legacy_contact_layout" {
		t.Fatalf("layout ID = %q, want first persisted fallback layout", layout.ID)
	}
	assertNoReadPathWrites(t, repo)
}

func TestResolveLayoutReturnsNonCuratedFallbackWithoutRuntimeAssignment(t *testing.T) {
	repo := newResolveLayoutFallbackRepo("Issue", []*models.PageLayout{{
		ID:                "auto_Issue_default",
		ObjectAPIName:     "Issue",
		LayoutName:        "Issue Layout",
		Source:            "auto_generated",
		GenerationVersion: currentGenerationVersion,
		Sections:          []models.PageSection{{ID: "details", Label: "Details", Fields: []string{"Name"}}},
	}})
	service := newResolveLayoutFallbackService(repo)

	layout := service.ResolveLayout(context.Background(), "Issue", nil, "", "")
	if layout == nil {
		t.Fatal("ResolveLayout returned nil, want non-curated fallback layout")
	}
	if layout.ID != "auto_Issue_default" {
		t.Fatalf("layout ID = %q, want auto_Issue_default", layout.ID)
	}
	assertNoReadPathWrites(t, repo)
}

func TestResolveLayoutForDescribeProjectsMissingNonCuratedLayout(t *testing.T) {
	repo := newResolveLayoutFallbackRepo("Issue", nil)
	service := newResolveLayoutFallbackService(repo)

	layout := service.ResolveLayout(context.Background(), "Issue", nil, "", "")
	if layout != nil {
		t.Fatalf("ResolveLayout returned %v, want nil authored layout", layout.ID)
	}
	assertNoReadPathWrites(t, repo)

	layout = service.ResolveLayoutForDescribe(context.Background(), "Issue", nil, "", "")
	if layout == nil {
		t.Fatal("ResolveLayoutForDescribe returned nil, want structural projection")
	}
	if layout.ID != "Issue-default-layout" {
		t.Fatalf("projection ID = %q, want Issue-default-layout", layout.ID)
	}
	if layout.LayoutName != "Issue-default-layout" {
		t.Fatalf("projection LayoutName = %q, want Issue-default-layout", layout.LayoutName)
	}
	if layout.Source != structuralProjectionSource {
		t.Fatalf("projection Source = %q, want %q", layout.Source, structuralProjectionSource)
	}
	if !layoutHasField(layout, "Name") || !layoutHasField(layout, "Subject") {
		t.Fatalf("projection fields = %+v, want structural business fields", layout.Sections)
	}
	assertNoReadPathWrites(t, repo)
}

func TestResolveLayoutSkipsOrphanedAssignmentWithoutDeleting(t *testing.T) {
	repo := newResolveLayoutFallbackRepo("Issue", []*models.PageLayout{{
		ID:            "live_Issue_default",
		ObjectAPIName: "Issue",
		LayoutName:    "Issue Layout",
		Source:        "curated",
		Sections:      []models.PageSection{{ID: "details", Label: "Details", Fields: []string{"Name"}}},
	}})
	repo.assignment = &models.LayoutAssignment{ID: "orphan", ObjectAPIName: "Issue", LayoutID: "missing_layout"}
	service := newResolveLayoutFallbackService(repo)

	layout := service.ResolveLayout(context.Background(), "Issue", nil, "", "")
	if layout == nil {
		t.Fatal("ResolveLayout returned nil, want fallback live layout")
	}
	if layout.ID != "live_Issue_default" {
		t.Fatalf("layout ID = %q, want live_Issue_default", layout.ID)
	}
	assertNoReadPathWrites(t, repo)
}

func assertNoReadPathWrites(t *testing.T, repo *resolveLayoutFallbackRepo) {
	t.Helper()
	if len(repo.upsertedLayouts) != 0 {
		t.Fatalf("UpsertLayout calls = %d, want 0", len(repo.upsertedLayouts))
	}
	if len(repo.createdAssignments) != 0 {
		t.Fatalf("CreateAssignment calls = %d, want 0", len(repo.createdAssignments))
	}
	if len(repo.deletedAssignments) != 0 {
		t.Fatalf("DeleteAssignment calls = %d, want 0", len(repo.deletedAssignments))
	}
	if len(repo.historyEntries) != 0 {
		t.Fatalf("WriteLayoutHistory calls = %d, want 0", len(repo.historyEntries))
	}
}

func newResolveLayoutFallbackService(repo *resolveLayoutFallbackRepo) *MetadataService {
	service := NewMetadataService(repo, nil, nil)
	service.coreCache.Store(&metadataSnapshot{
		schemas:   []*models.ObjectMetadata{repo.schema},
		schemaMap: map[string]*models.ObjectMetadata{strings.ToLower(repo.schema.APIName): repo.schema},
		fieldMap:  map[string][]models.FieldMetadata{strings.ToLower(repo.schema.APIName): repo.schema.Fields},
	})
	return service
}

func newResolveLayoutFallbackRepo(objectAPIName string, layouts []*models.PageLayout) *resolveLayoutFallbackRepo {
	return &resolveLayoutFallbackRepo{
		schema: &models.ObjectMetadata{
			APIName: objectAPIName,
			Fields: []models.FieldMetadata{
				{APIName: "Id", Label: "ID", Type: constants.FieldTypeString},
				{APIName: "Name", Label: "Name", Type: constants.FieldTypeString, IsNameField: true},
				{APIName: "Subject", Label: "Subject", Type: constants.FieldTypeString},
			},
		},
		layouts: layouts,
	}
}

type resolveLayoutFallbackRepo struct {
	ports.MetadataRepository

	schema             *models.ObjectMetadata
	assignment         *models.LayoutAssignment
	layouts            []*models.PageLayout
	upsertedLayouts    []*models.PageLayout
	createdAssignments []*models.LayoutAssignment
	deletedAssignments []string
	historyEntries     []*models.PageLayoutHistoryEntry
}

func (r *resolveLayoutFallbackRepo) FindBestAssignment(ctx context.Context, objectAPIName string, roleAncestors []string, profileID string, recordTypeID string) (*models.LayoutAssignment, error) {
	return r.assignment, nil
}

func (r *resolveLayoutFallbackRepo) GetLayouts(ctx context.Context, objectAPIName string) ([]*models.PageLayout, error) {
	return append([]*models.PageLayout(nil), r.layouts...), nil
}

func (r *resolveLayoutFallbackRepo) GetSchemaByAPIName(ctx context.Context, apiName string) (*models.ObjectMetadata, error) {
	return r.schema, nil
}

func (r *resolveLayoutFallbackRepo) GetLayout(ctx context.Context, id string) (*models.PageLayout, error) {
	for _, layout := range r.layouts {
		if layout != nil && layout.ID == id {
			return layout, nil
		}
	}
	for _, layout := range r.upsertedLayouts {
		if layout != nil && layout.ID == id {
			return layout, nil
		}
	}
	return nil, nil
}

func (r *resolveLayoutFallbackRepo) UpsertLayout(ctx context.Context, layout *models.PageLayout) error {
	r.upsertedLayouts = append(r.upsertedLayouts, cloneTestPageLayout(layout))
	return nil
}

func (r *resolveLayoutFallbackRepo) CreateAssignment(ctx context.Context, assignment *models.LayoutAssignment) error {
	clone := *assignment
	r.createdAssignments = append(r.createdAssignments, &clone)
	return nil
}

func (r *resolveLayoutFallbackRepo) DeleteAssignment(ctx context.Context, id string) error {
	r.deletedAssignments = append(r.deletedAssignments, id)
	return nil
}

func (r *resolveLayoutFallbackRepo) GetRelatedListConfigs(ctx context.Context, layoutObjectAPIName string) ([]ports.RelatedListConfig, error) {
	return nil, nil
}

func (r *resolveLayoutFallbackRepo) WriteLayoutHistory(ctx context.Context, entry *models.PageLayoutHistoryEntry) error {
	clone := *entry
	r.historyEntries = append(r.historyEntries, &clone)
	return nil
}

func (r *resolveLayoutFallbackRepo) GetLayoutHistoryMaxVersion(ctx context.Context, layoutID string) (int, error) {
	return 1, nil
}

func TestResolveLayoutServesStaleAutonumberLayoutWithoutRegeneration(t *testing.T) {
	// Schema with an autonumber name field (v2: Type=string, resolved via resolver)
	schema := &models.ObjectMetadata{
		APIName: "Quote",
		Fields: []models.FieldMetadata{
			{APIName: "Id", Label: "ID", Type: constants.FieldTypeString},
			{APIName: "Name", Label: "Quote Number", Type: constants.FieldTypeString, IsNameField: true},
			{APIName: "Status", Label: "Status", Type: constants.FieldTypeString},
		},
	}

	repo := &resolveLayoutFallbackRepo{
		schema: schema,
		// Stale auto_generated layout at v8 (one version below currentGenerationVersion=9),
		// with the autonumber name field already in an editable section
		layouts: []*models.PageLayout{{
			ID:                "auto_Quote_default",
			ObjectAPIName:     "Quote",
			LayoutName:        "Quote Layout",
			Source:            "auto_generated",
			GenerationVersion: currentGenerationVersion - 1, // stale: 8 < 9
			Sections: []models.PageSection{{
				ID:     "section_key",
				Label:  "Information",
				Fields: []string{"Name", "Status"}, // Name is the autonumber field
			}},
		}},
	}

	service := newResolveLayoutFallbackService(repo)
	// Wire the resolver so "Name" is recognized as an autonumber field
	service.SetAutoNumberFieldResolver(func(objectName string) map[string]struct{} {
		return map[string]struct{}{"Name": {}}
	})

	layout := service.ResolveLayout(context.Background(), "Quote", nil, "", "")
	if layout == nil {
		t.Fatal("ResolveLayout returned nil, want stale legacy layout")
	}

	assertNoReadPathWrites(t, repo)
	if layout.GenerationVersion != currentGenerationVersion-1 {
		t.Fatalf("layout GenerationVersion = %d, want stale version %d", layout.GenerationVersion, currentGenerationVersion-1)
	}

	// F1/F2/F3: autonumber field "Name" must be absent from ALL served editable sections.
	for _, section := range layout.Sections {
		for _, f := range section.Fields {
			if f == "Name" {
				t.Fatalf("autonumber field %q found in served layout section %q: %+v",
					"Name", section.Label, layout.Sections)
			}
		}
	}
}

// quoteSchemaWithAutonumberField builds a Quote schema that includes the v2
// autonumber field QuoteNumber (Type=string, resolver-set membership marks
// it autonumber). Used by the scrubber tests below.
func quoteSchemaWithAutonumberField() *models.ObjectMetadata {
	return &models.ObjectMetadata{
		APIName: "Quote",
		Fields: []models.FieldMetadata{
			{APIName: "Id", Label: "ID", Type: constants.FieldTypeString},
			{APIName: "Name", Label: "Name", Type: constants.FieldTypeString, IsNameField: true},
			{APIName: "QuoteNumber", Label: "Quote Number", Type: constants.FieldTypeString},
			{APIName: "Status", Label: "Status", Type: constants.FieldTypeString},
			{APIName: "OpportunityId", Label: "Opportunity", Type: constants.FieldTypeString},
		},
	}
}

// TestResolveLayoutScrubsAutonumberFromCuratedLayout — covers F8 (curated
// layout with an autonumber field in an editable section is scrubbed at
// read-time without regen / persistence). Subtests cover F10 (CompactLayout
// and RelatedLists preserved) and F11 (no-op when resolver is unwired).
func TestResolveLayoutScrubsAutonumberFromCuratedLayout(t *testing.T) {
	t.Run("strips_autonumber_from_section", func(t *testing.T) {
		repo := &resolveLayoutFallbackRepo{
			schema: quoteSchemaWithAutonumberField(),
			layouts: []*models.PageLayout{{
				ID:                "curated_Quote_default",
				ObjectAPIName:     "Quote",
				LayoutName:        "Quote Layout",
				Source:            "curated",
				GenerationVersion: currentGenerationVersion,
				Sections: []models.PageSection{{
					ID:     "quote_information",
					Label:  "Quote Information",
					Fields: []string{"Name", "QuoteNumber", "Status", "OpportunityId"},
				}},
			}},
		}
		service := newResolveLayoutFallbackService(repo)
		service.SetAutoNumberFieldResolver(func(objectName string) map[string]struct{} {
			return map[string]struct{}{"QuoteNumber": {}}
		})

		got := service.ResolveLayout(context.Background(), "Quote", nil, "", "")
		if got == nil {
			t.Fatal("ResolveLayout returned nil, want curated fallback layout")
		}
		// (1) Scrubber is read-time only: no regen, no upsert.
		if len(repo.upsertedLayouts) != 0 {
			t.Fatalf("UpsertLayout calls = %d, want 0 (read-time scrubber must not persist)", len(repo.upsertedLayouts))
		}
		// (2) Set-equality on the served section's Fields — catches a buggy
		// scrubber that drops extra fields OR re-orders them.
		want := []string{"Name", "Status", "OpportunityId"}
		if !reflect.DeepEqual(got.Sections[0].Fields, want) {
			t.Fatalf("section Fields = %v, want %v", got.Sections[0].Fields, want)
		}
	})

	t.Run("preserves_compact_and_related", func(t *testing.T) {
		compact := []string{"Name", "QuoteNumber", "Status", "OpportunityId"}
		related := []models.RelatedListConfig{{
			ID:            "items",
			Label:         "Items",
			ObjectAPIName: "QuoteItem",
			LookupField:   "QuoteId",
			Fields:        []string{"Name", "QuoteNumber", "Status"},
		}}
		repo := &resolveLayoutFallbackRepo{
			schema: quoteSchemaWithAutonumberField(),
			layouts: []*models.PageLayout{{
				ID:                "curated_Quote_default",
				ObjectAPIName:     "Quote",
				LayoutName:        "Quote Layout",
				Source:            "curated",
				GenerationVersion: currentGenerationVersion,
				CompactLayout:     append([]string(nil), compact...),
				RelatedLists:      append([]models.RelatedListConfig(nil), related...),
				Sections: []models.PageSection{{
					ID:     "quote_information",
					Label:  "Quote Information",
					Fields: []string{"Name", "QuoteNumber", "Status", "OpportunityId"},
				}},
			}},
		}
		service := newResolveLayoutFallbackService(repo)
		service.SetAutoNumberFieldResolver(func(objectName string) map[string]struct{} {
			return map[string]struct{}{"QuoteNumber": {}}
		})

		got := service.ResolveLayout(context.Background(), "Quote", nil, "", "")
		if got == nil {
			t.Fatal("ResolveLayout returned nil")
		}
		// CompactLayout: scrubber must NOT touch QuoteNumber here (Salesforce
		// v63 compact-identifier parity — the autonumber field IS the
		// human-facing identifier).
		if !reflect.DeepEqual(got.CompactLayout, compact) {
			t.Fatalf("CompactLayout = %v, want %v (scrubber must not touch CompactLayout)", got.CompactLayout, compact)
		}
		// RelatedLists: scrubber must NOT strip QuoteNumber from any
		// related list's Fields. (Note: repairLayoutRelatedLists runs
		// before the scrubber and may enrich SecondaryLabel; we assert on
		// Fields only.)
		if len(got.RelatedLists) != 1 {
			t.Fatalf("RelatedLists count = %d, want 1", len(got.RelatedLists))
		}
		wantRelatedFields := []string{"Name", "QuoteNumber", "Status"}
		if !reflect.DeepEqual(got.RelatedLists[0].Fields, wantRelatedFields) {
			t.Fatalf("RelatedLists[0].Fields = %v, want %v (scrubber must not strip QuoteNumber from related-list fields)", got.RelatedLists[0].Fields, wantRelatedFields)
		}
	})

	t.Run("noop_without_resolver", func(t *testing.T) {
		// Fresh fixture (sibling to the F8 fixture above) — the test mock
		// returns shared pointers, so each subtest builds its own *PageLayout.
		repo := &resolveLayoutFallbackRepo{
			schema: &models.ObjectMetadata{
				APIName: "Quote",
				// No autonumber-typed fields: this mirrors a system where no
				// autonumber resolver is wired AND the schema does not carry
				// FieldTypeAutonumber. Scrubber should be a no-op.
				Fields: []models.FieldMetadata{
					{APIName: "Id", Label: "ID", Type: constants.FieldTypeString},
					{APIName: "Name", Label: "Name", Type: constants.FieldTypeString, IsNameField: true},
					{APIName: "QuoteNumber", Label: "Quote Number", Type: constants.FieldTypeString},
					{APIName: "Status", Label: "Status", Type: constants.FieldTypeString},
					{APIName: "OpportunityId", Label: "Opportunity", Type: constants.FieldTypeString},
				},
			},
			layouts: []*models.PageLayout{{
				ID:                "curated_Quote_default",
				ObjectAPIName:     "Quote",
				LayoutName:        "Quote Layout",
				Source:            "curated",
				GenerationVersion: currentGenerationVersion,
				Sections: []models.PageSection{{
					ID:     "quote_information",
					Label:  "Quote Information",
					Fields: []string{"Name", "QuoteNumber", "Status", "OpportunityId"},
				}},
			}},
		}
		service := newResolveLayoutFallbackService(repo)
		// Deliberately DO NOT call SetAutoNumberFieldResolver.

		got := service.ResolveLayout(context.Background(), "Quote", nil, "", "")
		if got == nil {
			t.Fatal("ResolveLayout returned nil")
		}
		want := []string{"Name", "QuoteNumber", "Status", "OpportunityId"}
		if !reflect.DeepEqual(got.Sections[0].Fields, want) {
			t.Fatalf("section Fields = %v, want %v (scrubber must be no-op when resolver is unwired)", got.Sections[0].Fields, want)
		}
	})
}

// TestResolveLayoutScrubsDriftedAutonumberOnV9Layout — covers F9 (post-v9
// drift: an already-v9 auto_generated layout served after
// ApplyAutoNumberFormatSeeds mutates the resolver set must have the newly-
// autonumber field stripped on every read, without regen — because
// GenerationVersion == currentGenerationVersion so no regen fires).
func TestResolveLayoutScrubsDriftedAutonumberOnV9Layout(t *testing.T) {
	repo := &resolveLayoutFallbackRepo{
		schema: &models.ObjectMetadata{
			APIName: "Order",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Label: "ID", Type: constants.FieldTypeString},
				{APIName: "Name", Label: "Name", Type: constants.FieldTypeString, IsNameField: true},
				{APIName: "Quantity", Label: "Quantity", Type: constants.FieldTypeString},
				{APIName: "Status", Label: "Status", Type: constants.FieldTypeString},
			},
		},
		layouts: []*models.PageLayout{{
			ID:                "auto_Order_default",
			ObjectAPIName:     "Order",
			LayoutName:        "Order Layout",
			Source:            "auto_generated",
			GenerationVersion: currentGenerationVersion, // already current; no regen path
			Sections: []models.PageSection{{
				ID:     "details",
				Label:  "Details",
				Fields: []string{"Name", "Quantity", "Status"},
			}},
		}},
	}
	service := newResolveLayoutFallbackService(repo)
	// Resolver set after ApplyAutoNumberFormatSeeds promotes Quantity.
	service.SetAutoNumberFieldResolver(func(objectName string) map[string]struct{} {
		return map[string]struct{}{"Quantity": {}}
	})

	got := service.ResolveLayout(context.Background(), "Order", nil, "", "")
	if got == nil {
		t.Fatal("ResolveLayout returned nil")
	}
	// Critical: no UpsertLayout fired — GenerationVersion was already
	// current — but the field was still stripped. This is exactly the
	// drift scenario.
	if len(repo.upsertedLayouts) != 0 {
		t.Fatalf("UpsertLayout calls = %d, want 0 (post-v9 drift must not trigger regen)", len(repo.upsertedLayouts))
	}
	want := []string{"Name", "Status"}
	if !reflect.DeepEqual(got.Sections[0].Fields, want) {
		t.Fatalf("section Fields = %v, want %v", got.Sections[0].Fields, want)
	}
}

// TestGetLayoutByIDScrubsAutonumberFields — covers F12 (named-layout
// lookup via ?layoutId= path B). Subtest covers F11 (no-op when resolver
// is unwired) on path B.
func TestGetLayoutByIDScrubsAutonumberFields(t *testing.T) {
	t.Run("strips_autonumber_from_section", func(t *testing.T) {
		repo := &resolveLayoutFallbackRepo{
			schema: quoteSchemaWithAutonumberField(),
			layouts: []*models.PageLayout{{
				ID:                "curated_Quote_default",
				ObjectAPIName:     "Quote",
				LayoutName:        "Quote Layout",
				Source:            "curated",
				GenerationVersion: currentGenerationVersion,
				Sections: []models.PageSection{{
					ID:     "quote_information",
					Label:  "Quote Information",
					Fields: []string{"Name", "QuoteNumber", "Status"},
				}},
			}},
		}
		service := newResolveLayoutFallbackService(repo)
		service.SetAutoNumberFieldResolver(func(objectName string) map[string]struct{} {
			return map[string]struct{}{"QuoteNumber": {}}
		})

		got, err := service.GetLayoutByID(context.Background(), "curated_Quote_default")
		if err != nil {
			t.Fatalf("GetLayoutByID error = %v", err)
		}
		if got == nil {
			t.Fatal("GetLayoutByID returned nil layout")
		}
		want := []string{"Name", "Status"}
		if !reflect.DeepEqual(got.Sections[0].Fields, want) {
			t.Fatalf("section Fields = %v, want %v", got.Sections[0].Fields, want)
		}
	})

	t.Run("noop_when_unwired", func(t *testing.T) {
		// Sibling fixture: shared mock returns the seeded *PageLayout
		// pointer, so build a fresh one for this subtest.
		repo := &resolveLayoutFallbackRepo{
			schema: &models.ObjectMetadata{
				APIName: "Quote",
				Fields: []models.FieldMetadata{
					{APIName: "Id", Label: "ID", Type: constants.FieldTypeString},
					{APIName: "Name", Label: "Name", Type: constants.FieldTypeString, IsNameField: true},
					{APIName: "QuoteNumber", Label: "Quote Number", Type: constants.FieldTypeString},
					{APIName: "Status", Label: "Status", Type: constants.FieldTypeString},
				},
			},
			layouts: []*models.PageLayout{{
				ID:                "curated_Quote_default",
				ObjectAPIName:     "Quote",
				LayoutName:        "Quote Layout",
				Source:            "curated",
				GenerationVersion: currentGenerationVersion,
				Sections: []models.PageSection{{
					ID:     "quote_information",
					Label:  "Quote Information",
					Fields: []string{"Name", "QuoteNumber", "Status"},
				}},
			}},
		}
		service := newResolveLayoutFallbackService(repo)
		// Deliberately no resolver wired.

		got, err := service.GetLayoutByID(context.Background(), "curated_Quote_default")
		if err != nil {
			t.Fatalf("GetLayoutByID error = %v", err)
		}
		want := []string{"Name", "QuoteNumber", "Status"}
		if !reflect.DeepEqual(got.Sections[0].Fields, want) {
			t.Fatalf("section Fields = %v, want %v (must be no-op when resolver is unwired)", got.Sections[0].Fields, want)
		}
	})
}
