package layoutauthoringv1

import (
	"reflect"
	"sort"
	"testing"
)

// storedSectionVector deliberately has the current Core/L1 authoring shape,
// not the neutral shape: ordered placements and two independent maps, plus
// pointer-bearing stored scalars. These test-only adapters are executable
// evidence that the semantic IR can carry the producer facts losslessly.
type storedSectionVector struct {
	ID                  string
	Label               string
	Tab                 *string
	Type                *string
	ComponentName       *string
	Columns             uint32
	Fields              []string
	FieldLabels         map[string]string
	FieldBehaviors      map[string]map[string]string
	VisibilityCondition *string
}

func TestCoreAndL1SectionSourceVectorIsLossless(t *testing.T) {
	presentEmpty := ""
	condition := "record.Type == 'Partner'"
	source := storedSectionVector{
		ID: "section-main", Label: "Main", Tab: &presentEmpty, Type: nil,
		ComponentName: &presentEmpty, Columns: 2,
		Fields: []string{"Name", "OwnerId.Name"},
		FieldLabels: map[string]string{
			"Name":        "Account name",
			"Orphaned__c": "Retained orphan",
		},
		FieldBehaviors: map[string]map[string]string{
			"Empty__c":    {},
			"Name":        {"Create": "  Required  ", "quickCreate": "shown"},
			"Nil__c":      nil,
			"Orphaned__c": {"Edit": "hidden"},
		},
		VisibilityCondition: &condition,
	}

	neutral := neutralSectionFromStoredVector(source)
	document := validDocument()
	document.Tabs = []string{}
	document.Sections = []LayoutSection{neutral}
	if err := ValidateLayoutDocument(document); err != nil {
		t.Fatalf("source-derived neutral vector rejected: %v", err)
	}
	if roundTrip := storedVectorFromNeutralSection(neutral); !reflect.DeepEqual(roundTrip, source) {
		t.Fatalf("stored authoring facts changed\n got: %#v\nwant: %#v", roundTrip, source)
	}
}

func neutralSectionFromStoredVector(source storedSectionVector) LayoutSection {
	labels := make([]FieldLabel, 0, len(source.FieldLabels))
	for fieldReference, label := range source.FieldLabels {
		labels = append(labels, FieldLabel{FieldReference: fieldReference, Label: label})
	}
	sort.Slice(labels, func(left, right int) bool {
		return labels[left].FieldReference < labels[right].FieldReference
	})

	behaviors := make([]FieldBehaviorGroup, 0, len(source.FieldBehaviors))
	for fieldReference, byMode := range source.FieldBehaviors {
		if byMode == nil {
			behaviors = append(behaviors, FieldBehaviorGroup{FieldReference: fieldReference})
			continue
		}
		entries := make([]FieldBehavior, 0, len(byMode))
		for mode, behavior := range byMode {
			entries = append(entries, FieldBehavior{Mode: mode, Behavior: behavior})
		}
		sort.Slice(entries, func(left, right int) bool { return entries[left].Mode < entries[right].Mode })
		behaviors = append(behaviors, FieldBehaviorGroup{FieldReference: fieldReference, Behaviors: &entries})
	}
	sort.Slice(behaviors, func(left, right int) bool {
		return behaviors[left].FieldReference < behaviors[right].FieldReference
	})

	return LayoutSection{
		SectionID: source.ID, Label: source.Label, TabID: source.Tab, Kind: source.Type,
		ComponentName: source.ComponentName, ComponentConfiguration: []NamedValue{},
		Columns: source.Columns, Fields: append([]string(nil), source.Fields...),
		FieldLabels: labels, FieldBehaviors: behaviors, VisibilityCondition: source.VisibilityCondition,
	}
}

func storedVectorFromNeutralSection(section LayoutSection) storedSectionVector {
	labels := make(map[string]string, len(section.FieldLabels))
	for _, label := range section.FieldLabels {
		labels[label.FieldReference] = label.Label
	}
	behaviors := make(map[string]map[string]string)
	for _, group := range section.FieldBehaviors {
		if group.Behaviors == nil {
			behaviors[group.FieldReference] = nil
			continue
		}
		byMode := make(map[string]string, len(*group.Behaviors))
		for _, behavior := range *group.Behaviors {
			byMode[behavior.Mode] = behavior.Behavior
		}
		behaviors[group.FieldReference] = byMode
	}
	return storedSectionVector{
		ID: section.SectionID, Label: section.Label, Tab: section.TabID, Type: section.Kind,
		ComponentName: section.ComponentName, Columns: section.Columns,
		Fields: append([]string(nil), section.Fields...), FieldLabels: labels,
		FieldBehaviors: behaviors, VisibilityCondition: section.VisibilityCondition,
	}
}
