package layoutauthoringv1

// LayoutDocument is the complete caller-authorable Layout fact. Server-owned
// lifecycle, default/deleted state, optimistic versions, actor and Catalog
// lineage are intentionally represented only by stored/read wrappers.
type LayoutDocument struct {
	LayoutID             string            `json:"layout_id"`
	ObjectID             string            `json:"object_id"`
	Name                 string            `json:"name"`
	Kind                 string            `json:"kind"`
	LayoutVersion        uint32            `json:"layout_version"`
	CompactFields        []string          `json:"compact_fields"`
	Tabs                 []string          `json:"tabs"`
	Sections             []LayoutSection   `json:"sections"`
	RelatedLists         []RelatedList     `json:"related_lists"`
	RecordPanels         []RecordPanel     `json:"record_panels"`
	HeaderActions        ActionPlacement   `json:"header_actions"`
	QuickActions         ActionPlacement   `json:"quick_actions"`
	RecordStates         []RecordStateRule `json:"record_states"`
	PrimaryHeaderActions []string          `json:"primary_header_actions"`
}

// LayoutSection mirrors the stored authoring aggregate, not a rendering row.
// TabID, Kind, ComponentName, and VisibilityCondition are pointers because
// Core stores their absent and present-empty forms distinctly. Map-derived
// facts use present, sorted slices to provide one cross-transport form.
type LayoutSection struct {
	SectionID              string               `json:"section_id"`
	Label                  string               `json:"label"`
	TabID                  *string              `json:"tab_id,omitempty"`
	Kind                   *string              `json:"kind,omitempty"`
	ComponentName          *string              `json:"component_name,omitempty"`
	ComponentConfiguration []NamedValue         `json:"component_configuration"`
	Columns                uint32               `json:"columns"`
	Fields                 []string             `json:"fields"`
	FieldLabels            []FieldLabel         `json:"field_labels"`
	FieldBehaviors         []FieldBehaviorGroup `json:"field_behaviors"`
	VisibilityCondition    *string              `json:"visibility_condition,omitempty"`
}

// FieldLabel is one bytewise-sorted entry from the independently stored label
// map. FieldReference need not occur in Fields: Core deliberately preserves
// orphaned authoring entries when a field is removed from presentation.
type FieldLabel struct {
	FieldReference string `json:"field_reference"`
	Label          string `json:"label"`
}

// FieldBehaviorGroup is one bytewise-sorted outer-map entry. A nil Behaviors
// pointer preserves a present field key whose stored inner map is nil; a
// non-nil pointer must address a present, bytewise-sorted slice, including an
// authored-empty slice. Core's config fence observes nil and empty inner maps
// as different JSON facts (null versus {}).
type FieldBehaviorGroup struct {
	FieldReference string           `json:"field_reference"`
	Behaviors      *[]FieldBehavior `json:"behaviors,omitempty"`
}

// FieldBehavior is one mode/value entry. Both values are exact L1-owned
// bytes; L0 bounds them but never trims, normalizes, or interprets vocabulary.
type FieldBehavior struct {
	Mode     string `json:"mode"`
	Behavior string `json:"behavior"`
}

// RelatedList uses value scalars where Core does: an empty SecondaryLabel is
// the sole representation of no secondary label.
type RelatedList struct {
	RelatedListID   string           `json:"related_list_id"`
	Label           string           `json:"label"`
	SecondaryLabel  string           `json:"secondary_label"`
	ObjectID        string           `json:"object_id"`
	LookupFieldID   string           `json:"lookup_field_id"`
	FieldIDs        []string         `json:"field_ids"`
	PrefillMappings []PrefillMapping `json:"prefill_mappings"`
}

type PrefillMapping struct {
	TargetFieldID string `json:"target_field_id"`
	SourceFieldID string `json:"source_field_id"`
}

// RecordPanel's optional-looking strings are value fields in Core. Empty is
// therefore canonical; this contract does not invent pointer presence that
// the stored aggregate cannot retain.
type RecordPanel struct {
	PanelID               string       `json:"panel_id"`
	RendererID            string       `json:"renderer_id"`
	Position              string       `json:"position"`
	TabID                 string       `json:"tab_id"`
	TabLabel              string       `json:"tab_label"`
	Order                 int32        `json:"order"`
	VisibilityCondition   string       `json:"visibility_condition"`
	RendererConfiguration []NamedValue `json:"renderer_configuration"`
}

// ActionPlacement distinguishes inheritance (Authored=false, no actions) from
// an explicitly authored empty placement and an authored ordered action list.
type ActionPlacement struct {
	Authored bool           `json:"authored"`
	Actions  []LayoutAction `json:"actions"`
}

type LayoutAction struct {
	Name                string       `json:"name"`
	Label               string       `json:"label"`
	Kind                string       `json:"kind"`
	Icon                *string      `json:"icon,omitempty"`
	TargetObjectID      *string      `json:"target_object_id,omitempty"`
	Component           *string      `json:"component,omitempty"`
	VisibilityCondition *string      `json:"visibility_condition,omitempty"`
	Configuration       []NamedValue `json:"configuration"`
	Extensions          []NamedValue `json:"extensions"`
}

type RecordStateRule struct {
	RuleID          string                      `json:"rule_id"`
	Condition       string                      `json:"condition"`
	Priority        int32                       `json:"priority"`
	Banner          *RecordStateBanner          `json:"banner,omitempty"`
	Links           []RecordStateLink           `json:"links"`
	ActionOverrides []RecordStateActionOverride `json:"action_overrides"`
	ReadOnly        *RecordStateReadOnly        `json:"read_only,omitempty"`
}

// Record-state nested scalars are values in Core. Only the enclosing Banner
// and ReadOnly objects have presence semantics.
type RecordStateBanner struct {
	Severity string   `json:"severity"`
	Title    string   `json:"title"`
	Body     string   `json:"body"`
	LinkIDs  []string `json:"link_ids"`
}

type RecordStateLink struct {
	LinkID           string `json:"link_id"`
	Label            string `json:"label"`
	ReferenceFieldID string `json:"reference_field_id"`
	ObjectID         string `json:"object_id"`
	Placement        string `json:"placement"`
}

type RecordStateActionOverride struct {
	ActionKey string `json:"action_key"`
	Mode      string `json:"mode"`
	Reason    string `json:"reason"`
}

type RecordStateReadOnly struct {
	Enabled bool   `json:"enabled"`
	Reason  string `json:"reason"`
}

type ValueKind string

const (
	ValueNull    ValueKind = "NULL"
	ValueBoolean ValueKind = "BOOLEAN"
	ValueString  ValueKind = "STRING"
	ValueDecimal ValueKind = "DECIMAL"
	ValueList    ValueKind = "LIST"
	ValueObject  ValueKind = "OBJECT"
)

func (kind ValueKind) Valid() bool {
	switch kind {
	case ValueNull, ValueBoolean, ValueString, ValueDecimal, ValueList, ValueObject:
		return true
	default:
		return false
	}
}

// Value is the bounded closed union used for app-owned configuration and
// extension values. Object entries are strictly sorted and unique by Name.
type Value struct {
	Kind    ValueKind     `json:"kind"`
	Boolean *bool         `json:"boolean,omitempty"`
	String  *string       `json:"string,omitempty"`
	Decimal *string       `json:"decimal,omitempty"`
	List    *[]Value      `json:"list,omitempty"`
	Object  *[]NamedValue `json:"object,omitempty"`
}

type NamedValue struct {
	Name  string `json:"name"`
	Value Value  `json:"value"`
}
