package dialectsfcrm

import (
	"testing"

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

// describe/layouts reports the layout as authored and does not apply the
// per-mode narrowing that the UI API layout response applies (NexusCRM#3506,
// owner ruling). That is a deliberate divergence between two endpoints, which
// makes it exactly the kind of claim that decays into a lie: the next reader
// sees a behavior map going unused and "fixes" it. This pins it, so making the
// converter behavior-aware requires deleting an assertion that says why not.
func TestDescribeLayoutsIsBehaviorBlindOnPurpose(t *testing.T) {
	schema := &models.ObjectMetadata{
		APIName: "Account",
		Fields: []models.FieldMetadata{
			{APIName: constants.FieldName, Label: "Account Name", Type: constants.FieldTypeString, Createable: true, Updateable: true},
			{APIName: "Rating__c", Label: "Rating", Type: constants.FieldTypeString, Createable: true, Updateable: true},
		},
	}
	layout := &models.PageLayout{
		ID:            "curated_Account_default",
		ObjectAPIName: "Account",
		LayoutName:    "Account Layout",
		Sections: []models.PageSection{{
			ID:      "s1",
			Label:   "Account Information",
			Columns: 2,
			Fields:  []string{constants.FieldName, "Rating__c"},
			// Hidden in every mode the UI API honors, and in the one it does not.
			FieldBehaviors: map[string]map[string]string{"Rating__c": {
				"create": "hidden", "edit": "hidden", "detail": "hidden",
			}},
		}},
	}

	out := convertStoredLayoutToSFFormat(layout, schema, nil)

	for _, key := range []string{"sections", "detailLayoutSections", "editLayoutSections"} {
		sections, ok := out[key].([]map[string]any)
		if !ok || len(sections) == 0 {
			t.Fatalf("%s = %#v, want at least one section", key, out[key])
		}
		if !describeSectionMentions(t, sections[0], "Rating__c") {
			t.Errorf("%s dropped Rating__c. If that was intentional, the divergence "+
				"stated on convertStoredLayoutToSFFormat and in the v63 carve-out is now "+
				"wrong and both have to change with it — this endpoint reports what the "+
				"layout contains, not what one form renders", key)
		}
	}
}

// describeSectionMentions reports whether the field appears in the section.
// The two section shapes this converter emits are genuinely different
// projections, not two halves of one: "sections" carries a raw field list and no
// rows, while detail/editLayoutSections carry rendered rows and no field list.
// So this checks whichever the section actually has, and fails a section that
// has neither rather than silently reporting absence.
func describeSectionMentions(t *testing.T, section map[string]any, fieldName string) bool {
	t.Helper()
	if fields, ok := section["fields"].([]string); ok {
		for _, f := range fields {
			if f == fieldName {
				return true
			}
		}
		return false
	}
	rows, ok := section["layoutRows"].([]map[string]any)
	if !ok {
		t.Fatalf("section has neither a field list nor rendered rows, so this test "+
			"cannot tell presence from absence: %#v", section)
	}
	for _, row := range rows {
		items, _ := row["layoutItems"].([]map[string]any)
		for _, item := range items {
			if name, _ := item["field"].(string); name == fieldName {
				return true
			}
		}
	}
	return false
}
