package models

import (
	"encoding/json"
	"strings"
	"time"

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

// PicklistOption represents a single picklist option with value and display label.
//
// Tags is a tenant-authored classification set used by generic Flow operators
// (e.g. EntersPickTag) to decide whether a Status transition should fire
// downstream logic, without the platform knowing about the tag's semantics.
// Platform code must never compare Tags string literals; it only asks
// "does option X carry tag Y?" The business meaning lives entirely in the
// tenant spec that populates Tags.
//
// Tags is preserved only for the structured JSON form
// `{"value":"X","label":"Y","tags":["t"]}`. The legacy `["v1","v2"]` form
// (see UnmarshalJSON below) cannot carry tags — callers that want tags
// must author the picklist in structured form.
type PicklistOption struct {
	Value string   `json:"value"`
	Label string   `json:"label"`
	Tags  []string `json:"tags,omitempty"`
}

// PicklistOptions is a slice of PicklistOption that supports backward-compatible
// JSON unmarshaling: both legacy ["v1","v2"] and new [{"value":"v1","label":"L1"},...] formats.
type PicklistOptions []PicklistOption

func (po PicklistOptions) Values() []string {
	out := make([]string, len(po))
	for i, o := range po {
		out[i] = o.Value
	}
	return out
}

func (po PicklistOptions) Len() int { return len(po) }

func (po *PicklistOptions) UnmarshalJSON(data []byte) error {
	if len(data) == 0 || string(data) == "null" {
		*po = nil
		return nil
	}

	// Try legacy format first: ["v1","v2"] — value == label
	var plain []string
	if err := json.Unmarshal(data, &plain); err == nil {
		opts := make(PicklistOptions, len(plain))
		for i, v := range plain {
			opts[i] = PicklistOption{Value: v, Label: v}
		}
		*po = opts
		return nil
	}

	// New structured format: [{"value":"...","label":"..."},...]
	// Tried second because json.Unmarshal into []PicklistOption silently
	// succeeds on ["v1","v2"] (producing zero-value structs), losing data.
	var structured []PicklistOption
	if err := json.Unmarshal(data, &structured); err == nil {
		*po = structured
		return nil
	}

	return nil
}

// MarshalJSON always writes the new structured format.
func (po PicklistOptions) MarshalJSON() ([]byte, error) {
	if po == nil {
		return []byte("null"), nil
	}
	type alias []PicklistOption
	return json.Marshal(alias(po))
}

// PicklistOptionsFromStrings creates PicklistOptions from plain string values (value==label).
func PicklistOptionsFromStrings(vals []string) PicklistOptions {
	if vals == nil {
		return nil
	}
	opts := make(PicklistOptions, len(vals))
	for i, v := range vals {
		opts[i] = PicklistOption{Value: v, Label: v}
	}
	return opts
}

// FieldType is defined in pkg/constants
type FieldType = constants.SchemaFieldType

// SharingModel is defined in pkg/constants
type SharingModel = constants.SharingModel

// DeleteRule is defined in pkg/constants
type DeleteRule = constants.DeleteRule

// RollupConfig represents rollup summary field configuration
type RollupConfig struct {
	SummaryObject     string  `json:"summaryObject"`
	SummaryField      string  `json:"summaryField"`
	RelationshipField string  `json:"relationshipField"` // The lookup field on the child object
	CalcType          string  `json:"calcType"`          // COUNT, SUM, MIN, MAX, AVG
	Filter            *string `json:"filter,omitempty"`
}

// FieldMetadata represents field-level metadata
type FieldMetadata struct {
	ID           string     `json:"id,omitempty"`
	APIName      string     `json:"name"`
	PhysicalName string     `json:"-"` // Actual DB column name if aliased
	Label        string     `json:"label"`
	Type         FieldType  `json:"type"`
	LogicalType  *FieldType `json:"logicalType,omitempty"` // Derived from system_tables.json for standard objects
	Required     bool       `json:"required,omitempty"`
	IsUnique     bool       `json:"unique,omitempty"`
	IsNameField  bool       `json:"nameField,omitempty"`
	// Source is the provenance classifier for this field. One of:
	// managed, standard_spec, tenant_spec, custom, bootstrap_seed, discovered.
	// Introduced by issue #1582 RFC v1.5. Governs ComputeIntrinsic Layer 1d.
	Source string `json:"source,omitempty"`
	// IsCompound marks fields whose value is derived from ComposedFrom members
	// (e.g., User.Name from FirstName+LastName). Read-only on write per SF parity.
	// Introduced by issue #1582 RFC v1.5. Governs ComputeIntrinsic Layer 1e.
	IsCompound bool `json:"isCompound,omitempty"`
	// ComposedFrom lists the member field ApiNames a compound parent derives from.
	// Nil/empty when IsCompound is false. Introduced by issue #1582 RFC v1.5.
	ComposedFrom       []string            `json:"composedFrom,omitempty"`
	Options            PicklistOptions     `json:"options,omitempty"`
	ReferenceTo        []string            `json:"referenceTo,omitempty"` // Supports polymorphic (multiple objects)
	IsPolymorphic      bool                `json:"polymorphic,omitempty"` // True if len(ReferenceTo) > 1
	DeleteRule         *DeleteRule         `json:"deleteRule,omitempty"`
	IsSystem           bool                `json:"system,omitempty"`
	Createable         bool                `json:"createable"`
	Updateable         bool                `json:"updateable"`
	Formula            *string             `json:"formula,omitempty"`
	ReturnType         *FieldType          `json:"returnType,omitempty"`
	FormulaMode        *string             `json:"formulaMode,omitempty"` // "active" (Go engine computes) or "frozen" (last synced value)
	DefaultValue       *string             `json:"defaultValue,omitempty"`
	HelpText           *string             `json:"inlineHelpText,omitempty"`
	TrackHistory       bool                `json:"trackHistory,omitempty"`
	MinValue           *float64            `json:"minValue,omitempty"`
	MaxValue           *float64            `json:"maxValue,omitempty"`
	MinLength          *int                `json:"minLength,omitempty"`
	MaxLength          *int                `json:"maxLength,omitempty"`
	Regex              *string             `json:"regex,omitempty"`
	RegexMessage       *string             `json:"regexMessage,omitempty"`
	Validator          *string             `json:"validator,omitempty"`
	ValidatorConfig    *string             `json:"validatorConfig,omitempty"` // JSON config for the validator
	ControllingField   *string             `json:"controllingField,omitempty"`
	PicklistDependency map[string][]string `json:"picklistDependency,omitempty"`
	RollupConfig       *RollupConfig       `json:"rollupConfig,omitempty"`
	IsMasterDetail     bool                `json:"masterDetail,omitempty"`
	RelationshipName   *string             `json:"relationshipName,omitempty"`
	Precision          *int                `json:"precision,omitempty"`
	Scale              *int                `json:"scale,omitempty"`

	// IsVirtual marks fields that have no physical column in the object's
	// storage table. Physical SQL paths (INSERT/UPDATE/SELECT column lists,
	// repository column helpers) must skip these via models.PersistableFields.
	// Logical paths (validation, canonicalization, FLS, describe) continue
	// to see them via schema.Fields or models.LogicalFields.
	//
	// Any field with IsVirtual=true must declare VirtualKind; the kind
	// selects the handler responsible for intercepting writes and
	// projecting reads for that field.
	IsVirtual bool `json:"isVirtual,omitempty"`

	// VirtualKind identifies the handler class for a virtual field. See
	// constants.VirtualFieldKind for the enumerated values. Empty for
	// non-virtual fields.
	VirtualKind string `json:"virtualKind,omitempty"`

	// VirtualSourceAPIName is the kind-specific key that the handler uses
	// to translate between the field's wire-shape APIName and the
	// underlying data. Example: for a PermissionSet virtual field with
	// APIName "PermissionsViewSetup" and VirtualKind "SystemPermission",
	// VirtualSourceAPIName is "ViewSetup" — the catalog key without the
	// "Permissions" prefix. Downstream handlers read this directly; they
	// must not string-trim APIName themselves.
	VirtualSourceAPIName string `json:"virtualSourceApiName,omitempty"`
}

// ChildCloneRule declares a post-insert side effect: when a record of the
// containing object is created with ParentLookupField populated, every
// SourceObject row linked via SourceLookupField to the referenced parent is
// cloned into a TargetObject row linked via TargetLookupField to the newly
// created record. Field values are carried over per FieldMappings (flat
// key:source-key pairs, no dotted paths). Optional SourceIdField stamps the
// source row's Id onto the clone as a back-reference. HydrateSource, when
// true, retrieves each source row through the normal Retrieve path so
// formula/computed fields are populated before copy.
//
// Authored per-tenant on `_System_Object.ChildCloneRules`; greenfield orgs
// leave the column NULL and the generic post-insert hook in
// features/records/persistence_insert.go no-ops. The executor is shared with
// the REST action handler's workflow.childCopy via features/records/child_clone.go.
type ChildCloneRule struct {
	ParentLookupField string            `json:"parentLookupField"`
	SourceObject      string            `json:"sourceObject"`
	SourceLookupField string            `json:"sourceLookupField"`
	SourceIdField     string            `json:"sourceIdField,omitempty"`
	HydrateSource     bool              `json:"hydrateSource,omitempty"`
	TargetObject      string            `json:"targetObject"`
	TargetLookupField string            `json:"targetLookupField"`
	FieldMappings     map[string]string `json:"fieldMappings"`
}

// ObjectAccessPolicy declares metadata-authored object/field access as a
// composition of canonical object/system permission checks.
type ObjectAccessPolicy struct {
	Mode         string            `json:"mode,omitempty"`
	ObjectRead   *AccessPolicyExpr `json:"objectRead,omitempty"`
	ObjectCreate *AccessPolicyExpr `json:"objectCreate,omitempty"`
	ObjectEdit   *AccessPolicyExpr `json:"objectEdit,omitempty"`
	ObjectDelete *AccessPolicyExpr `json:"objectDelete,omitempty"`
	FieldRead    *AccessPolicyExpr `json:"fieldRead,omitempty"`
	FieldEdit    *AccessPolicyExpr `json:"fieldEdit,omitempty"`
}

// IsDerived reports whether the policy declares a derived/composite access
// surface that should not own self ObjectPermissions / FieldPermissions rows.
func (p *ObjectAccessPolicy) IsDerived() bool {
	return p != nil && strings.EqualFold(strings.TrimSpace(p.Mode), "derived")
}

// AccessPolicyExpr is a recursive predicate tree over canonical permissions.
type AccessPolicyExpr struct {
	Kind      string             `json:"kind,omitempty"`
	Object    string             `json:"object,omitempty"`
	Operation string             `json:"operation,omitempty"`
	APIName   string             `json:"apiName,omitempty"`
	Field     string             `json:"field,omitempty"`
	AllOf     []AccessPolicyExpr `json:"allOf,omitempty"`
	AnyOf     []AccessPolicyExpr `json:"anyOf,omitempty"`
	Not       *AccessPolicyExpr  `json:"not,omitempty"`
	Inherit   string             `json:"inherit,omitempty"`
}

// ObjectMetadata represents object-level metadata
type ObjectMetadata struct {
	ID                      string                    `json:"id,omitempty"`
	AppID                   *string                   `json:"appId,omitempty"`
	APIName                 string                    `json:"name"`
	Label                   string                    `json:"label"`
	PluralLabel             string                    `json:"labelPlural"`
	Icon                    string                    `json:"icon,omitempty"`
	Description             *string                   `json:"description,omitempty"`
	IsSystem                bool                      `json:"system,omitempty"`
	IsCustom                bool                      `json:"custom,omitempty"`
	TableType               constants.TableType       `json:"tableType,omitempty"`
	RequiredWritePermission string                    `json:"requiredWritePermission,omitempty"`
	RequiredReadPermission  string                    `json:"requiredReadPermission,omitempty"`
	AccessPolicy            *ObjectAccessPolicy       `json:"accessPolicy,omitempty"`
	DeleteMode              string                    `json:"deleteMode,omitempty"`
	ThemeColor              *string                   `json:"themeColor,omitempty"`
	SharingModel            SharingModel              `json:"sharingModel"`
	IsCustomized            bool                      `json:"isCustomized,omitempty"`
	EnableHierarchySharing  bool                      `json:"enableHierarchySharing"`
	Fields                  []FieldMetadata           `json:"fields"`
	DefaultListView         *string                   `json:"defaultListView,omitempty"`
	KanbanGroupBy           *string                   `json:"kanbanGroupBy,omitempty"`
	KanbanSummaryField      *string                   `json:"kanbanSummaryField,omitempty"`
	ListFields              []string                  `json:"listFields,omitempty"`
	ChildCloneRules         []ChildCloneRule          `json:"childCloneRules,omitempty"`
	Searchable              bool                      `json:"searchable"`
	PathField               *string                   `json:"pathField,omitempty"` // Field to use for Path component (must be Picklist)
	FieldsMap               map[string]*FieldMetadata `json:"-"`                   // Runtime lookup map for O(1) access
}

// UsesDerivedAccessPolicy reports whether the object's access surface is fully
// derived from other canonical permissions instead of self OP/FP rows.
func (o *ObjectMetadata) UsesDerivedAccessPolicy() bool {
	return o != nil && o.AccessPolicy != nil && o.AccessPolicy.IsDerived()
}

// ListView represents a list view configuration
type ListView struct {
	ID            string `json:"id"`
	ObjectAPIName string `json:"objectApiName"`
	Label         string `json:"label"`

	FilterExpr string   `json:"filterExpr,omitempty"`
	Fields     []string `json:"fields,omitempty"`
}

// PageLayout represents page layout configuration
type PageLayout struct {
	ID                string              `json:"id"`
	ObjectAPIName     string              `json:"objectApiName"`
	LayoutName        string              `json:"layoutName"`
	Type              string              `json:"type,omitempty"` // Detail, Edit, Create, List
	IsDefault         bool                `json:"isDefault,omitempty"`
	IsDeleted         bool                `json:"isDeleted,omitempty"`
	CompactLayout     []string            `json:"compactLayout"`
	Tabs              []string            `json:"tabs,omitempty"`
	Sections          []PageSection       `json:"sections"`
	RelatedLists      []RelatedListConfig `json:"relatedLists"`
	HeaderActions     []ActionConfig      `json:"headerActions"`
	QuickActions      []ActionConfig      `json:"quickActions"`
	IsCustomized      bool                `json:"isCustomized,omitempty"`      // DEPRECATED: use Source
	LayoutVersion     int                 `json:"layoutVersion,omitempty"`     // DEPRECATED: use GenerationVersion
	Source            string              `json:"source,omitempty"`            // auto_generated, admin_created, cloned, curated
	GenerationVersion int                 `json:"generationVersion,omitempty"` // Algorithm version (only for Source=auto_generated)
	CreatedDate       time.Time           `json:"createdDate,omitempty"`
	LastModifiedDate  time.Time           `json:"lastModifiedDate,omitempty"`
}

// LayoutAssignment maps a (Role x Profile x RecordType) combination to a PageLayout.
// NULL dimensions are wildcards ("any"). Specificity = count of non-NULL dimensions.
const (
	LayoutAssignmentRouteSourceRuntimeFallback = "runtime_fallback"
	LayoutAssignmentRouteSourceManagedSeed     = "managed_seed"
	LayoutAssignmentRouteSourceAdminAuthored   = "admin_authored"
)

type LayoutAssignment struct {
	ID               string    `json:"id"`
	ObjectAPIName    string    `json:"objectApiName"`
	LayoutID         string    `json:"layoutId"`
	RoleID           *string   `json:"roleId,omitempty"`
	ProfileID        *string   `json:"profileId,omitempty"`
	RecordTypeID     *string   `json:"recordTypeId,omitempty"`
	RouteSource      *string   `json:"-"`
	Specificity      int       `json:"specificity"`
	CreatedDate      time.Time `json:"createdDate,omitempty"`
	LastModifiedDate time.Time `json:"lastModifiedDate,omitempty"`
	CreatedByID      *string   `json:"createdById,omitempty"`
}

// Normalize converts empty-string dimension pointers to nil.
// Prevents "phantom" assignments where an empty string has specificity 1 but never matches.
func (la *LayoutAssignment) Normalize() {
	if la.RoleID != nil && *la.RoleID == "" {
		la.RoleID = nil
	}
	if la.ProfileID != nil && *la.ProfileID == "" {
		la.ProfileID = nil
	}
	if la.RecordTypeID != nil && *la.RecordTypeID == "" {
		la.RecordTypeID = nil
	}
}

// ComputeSpecificity calculates the specificity from non-NULL dimensions.
func (la *LayoutAssignment) ComputeSpecificity() int {
	s := 0
	if la.RoleID != nil {
		s++
	}
	if la.ProfileID != nil {
		s++
	}
	if la.RecordTypeID != nil {
		s++
	}
	la.Specificity = s
	return s
}

// PageLayoutHistoryEntry is a content version snapshot for undo/rollback.
type PageLayoutHistoryEntry struct {
	ID            string    `json:"id"`
	LayoutID      string    `json:"layoutId"`
	VersionNumber int       `json:"versionNumber"`
	Config        string    `json:"config"` // raw JSON snapshot
	ChangedByID   *string   `json:"changedById,omitempty"`
	ChangeReason  string    `json:"changeReason"`
	CreatedDate   time.Time `json:"createdDate"`
}

// PageSection represents a section in a page layout
type PageSection struct {
	ID                  string                 `json:"id"`
	Label               string                 `json:"label"`
	Tab                 *string                `json:"tab,omitempty"`
	Type                *string                `json:"type,omitempty"` // Fields, Component
	ComponentName       *string                `json:"componentName,omitempty"`
	ComponentConfig     map[string]interface{} `json:"componentConfig,omitempty"`
	Columns             int                    `json:"columns"`
	Fields              []string               `json:"fields"`
	FieldLabels         map[string]string      `json:"fieldLabels,omitempty"`
	VisibilityCondition *string                `json:"visibilityCondition,omitempty"`
}

// RelatedListConfig represents a related list configuration
type RelatedListConfig struct {
	ID              string            `json:"id"`
	Label           string            `json:"label"`
	SecondaryLabel  string            `json:"secondaryLabel,omitempty"`
	ObjectAPIName   string            `json:"objectApiName"`
	LookupField     string            `json:"lookupField"`
	Fields          []string          `json:"fields"`
	PrefillMappings map[string]string `json:"prefillMappings,omitempty"`
}

// ActionConfig represents an action configuration
type ActionConfig struct {
	Name                string                 `json:"name"`
	Label               string                 `json:"label"`
	Type                string                 `json:"type"` // Standard, CreateRecord, UpdateRecord, Flow, Custom, Url
	Icon                *string                `json:"icon,omitempty"`
	TargetObject        *string                `json:"targetObject,omitempty"`
	Config              map[string]interface{} `json:"config,omitempty"`
	VisibilityCondition *string                `json:"visibilityCondition,omitempty"`
	Component           *string                `json:"component,omitempty"`
}

// ActionMetadata represents action metadata
type ActionMetadata struct {
	ID            string                 `json:"id"`
	ObjectAPIName string                 `json:"objectApiName"`
	Name          string                 `json:"name"`
	Label         string                 `json:"label"`
	Type          string                 `json:"type"`
	Icon          string                 `json:"icon"`
	TargetObject  *string                `json:"targetObject,omitempty"`
	Config        map[string]interface{} `json:"config,omitempty"`
}

type RecordType struct {
	ID                string    `json:"id"`
	ObjectAPIName     string    `json:"objectApiName"`
	Name              string    `json:"name"`
	Label             string    `json:"label"`
	Description       *string   `json:"description,omitempty"`
	IsActive          bool      `json:"isActive"`
	IsDefault         bool      `json:"isDefault"`
	BusinessProcessID *string   `json:"businessProcessId,omitempty"`
	CreatedDate       time.Time `json:"createdDate"`
	LastModifiedDate  time.Time `json:"lastModifiedDate"`
}

type AutoNumber struct {
	ID               string    `json:"id"`
	ObjectAPIName    string    `json:"objectApiName"`
	FieldAPIName     string    `json:"fieldApiName"`
	DisplayFormat    string    `json:"displayFormat"`
	StartingNumber   int       `json:"startingNumber"`
	CurrentValue     int       `json:"currentValue"`
	CreatedDate      time.Time `json:"createdDate"`
	LastModifiedDate time.Time `json:"lastModifiedDate"`
}

// IdentifierRule is the canonical in-memory representation of a row from
// `_System_IdentifierRule` (the Unified Identifier Engine — see
// docs/design/unified-identifier-engine.md).
//
// JSON tags on TargetFields, FieldLookups, IdentifierFieldLookup, and
// IdentifierLookupStep MUST stay in lock-step with the seed payload written
// by `controlplane/packs.applyIdentifierRules` (Task 1). Otherwise rows
// loaded from DB lose fields when JSON-decoded back into this struct.
type IdentifierRule struct {
	ID            string                           `json:"id"`
	ObjectAPIName string                           `json:"objectApiName"`
	RuleName      string                           `json:"ruleName"`
	Template      string                           `json:"template"`
	TargetFields  map[string]string                `json:"targetFields"`
	FieldLookups  map[string]IdentifierFieldLookup `json:"fieldLookups"`
	IsActive      bool                             `json:"isActive"`
}

// IdentifierFieldLookup describes how to resolve a single template variable
// (e.g. "Account.BillingCountryCode") for a record. Mirrors the structure
// produced by IdentifierRuleSeeds() in controlplane/packs/platform_config.go.
type IdentifierFieldLookup struct {
	DirectField string                   `json:"directField,omitempty"`
	Chains      [][]IdentifierLookupStep `json:"chains"`
}

// IdentifierLookupStep is one hop in an FK resolution chain.
type IdentifierLookupStep struct {
	FKField     string `json:"fkField"`
	TargetTable string `json:"targetTable"`
	TargetField string `json:"targetField"`
}

type Relationship struct {
	ID                  string    `json:"id"`
	ChildObjectAPIName  string    `json:"childObjectApiName"`
	ParentObjectAPIName string    `json:"parentObjectApiName"`
	FieldAPIName        string    `json:"fieldApiName"`
	RelationshipName    string    `json:"relationshipName"`
	RelationshipType    string    `json:"relationshipType"`
	IsSharingParent     bool      `json:"isSharingParent"`
	CascadeDelete       bool      `json:"cascadeDelete"`
	RestrictedDelete    bool      `json:"restrictedDelete"`
	RelatedListLabel    *string   `json:"relatedListLabel,omitempty"`
	RelatedListFields   *string   `json:"relatedListFields,omitempty"`
	CreatedDate         time.Time `json:"createdDate"`
	LastModifiedDate    time.Time `json:"lastModifiedDate"`
}

type FieldDependency struct {
	ID               string    `json:"id"`
	ObjectAPIName    string    `json:"objectApiName"`
	ControllingField string    `json:"controllingField"`
	DependentField   string    `json:"dependentField"`
	ControllingValue string    `json:"controllingValue"`
	DependentValues  []string  `json:"dependentValues"`
	IsActive         bool      `json:"isActive"`
	CreatedDate      time.Time `json:"createdDate"`
	LastModifiedDate time.Time `json:"lastModifiedDate"`
}

// ValidationRule represents a validation rule
type ValidationRule struct {
	ID                string  `json:"id"`
	ObjectAPIName     string  `json:"objectApiName"`
	Name              string  `json:"name"`
	Description       *string `json:"description,omitempty"`
	Active            bool    `json:"active"`
	Condition         string  `json:"condition"`
	ErrorMessage      string  `json:"errorMessage"`
	ErrorDisplayField *string `json:"errorDisplayField,omitempty"`
	IsCustomized      bool    `json:"isCustomized"`
}

// NavigationItem represents a navigation item in an app
type NavigationItem struct {
	ID            string `json:"id"`
	Type          string `json:"type"` // object, page, web, dashboard
	ObjectAPIName string `json:"objectApiName,omitempty"`
	PageURL       string `json:"pageUrl,omitempty"`
	DashboardID   string `json:"dashboardId,omitempty"`
	Label         string `json:"label"`
	Icon          string `json:"icon"`
}

// UtilityItem represents a utility bar item in an app (Salesforce Lightning parity)
type UtilityItem struct {
	ID          string `json:"id"`
	Type        string `json:"type"` // notes, recent, history, custom
	Label       string `json:"label"`
	Icon        string `json:"icon"`
	PanelWidth  *int   `json:"panelWidth,omitempty"`
	PanelHeight *int   `json:"panelHeight,omitempty"`
}

// AppConfig represents application configuration
type AppConfig struct {
	ID               string           `json:"id"`
	Label            string           `json:"label"`
	Description      string           `json:"description"`
	Icon             string           `json:"icon"`
	Color            string           `json:"color"`
	IsDefault        bool             `json:"isDefault"`
	NavigationItems  []NavigationItem `json:"navigationItems,omitempty"`
	UtilityItems     []UtilityItem    `json:"utilityItems,omitempty"`
	AssignedProfiles []string         `json:"assignedProfiles,omitempty"`
	CreatedDate      time.Time        `json:"createdDate,omitempty"`
	LastModifiedDate time.Time        `json:"lastModifiedDate,omitempty"`
}

// Theme represents a visual theme
type Theme struct {
	ID               string                 `json:"id"`
	Name             string                 `json:"name"`
	IsActive         bool                   `json:"isActive"`
	Colors           map[string]interface{} `json:"colors"`
	Density          string                 `json:"density"`
	LogoURL          *string                `json:"logoUrl,omitempty"`
	CreatedDate      time.Time              `json:"createdDate,omitempty"`
	LastModifiedDate time.Time              `json:"lastModifiedDate,omitempty"`
}

// DashboardConfig represents dashboard configuration
type DashboardConfig struct {
	ID            string         `json:"id"`
	DeveloperName string         `json:"developerName"`
	Label         string         `json:"label"`
	Description   *string        `json:"description,omitempty"`
	Layout        string         `json:"layout,omitempty"`
	LayoutMode    string         `json:"layoutMode,omitempty"` // auto = smart layout, fixed = use exact positions
	FilterMode    string         `json:"filterMode,omitempty"` // none = no filters, date = date only, full = all filters
	StartDate     *string        `json:"startDate,omitempty"`  // YYYY-MM-DD
	EndDate       *string        `json:"endDate,omitempty"`    // YYYY-MM-DD
	DateRangeType string         `json:"dateRangeType,omitempty"`
	DashboardType string         `json:"dashboardType,omitempty"` // SpecifiedUser, LoggedInUser, MyTeamUser
	RunningUserId string         `json:"runningUserId,omitempty"` // User whose RLS is used for SpecifiedUser/MyTeamUser
	Widgets       []WidgetConfig `json:"widgets"`
}

// WidgetConfig represents a dashboard widget
type WidgetConfig struct {
	ID        string                 `json:"id"`
	Title     string                 `json:"title"`
	Type      string                 `json:"type"`
	ReportID  string                 `json:"reportId,omitempty"` // Report-First: widgets reference Salesforce Reports
	Config    map[string]interface{} `json:"config,omitempty"`   // Widget-specific settings
	X         *int                   `json:"x,omitempty"`
	Y         *int                   `json:"y,omitempty"`
	W         *int                   `json:"w,omitempty"`
	H         *int                   `json:"h,omitempty"`
	Icon      *string                `json:"icon,omitempty"`
	Color     *string                `json:"color,omitempty"`
	DateField *string                `json:"dateField,omitempty"`
}

type ProfileLayoutAssignment struct {
	LayoutID string `json:"layoutId"`
}

// SetupPage represents a page in the setup area
type SetupPage struct {
	ID                 string    `json:"id"`
	Label              string    `json:"label"`
	Icon               string    `json:"icon"`
	ComponentName      string    `json:"componentName"`
	Category           string    `json:"category"`
	PageOrder          int       `json:"pageOrder"`
	PermissionRequired string    `json:"permissionRequired,omitempty"`
	IsEnabled          bool      `json:"isEnabled"`
	Description        string    `json:"description,omitempty"`
	Path               string    `json:"path,omitempty"`
	CreatedDate        time.Time `json:"createdDate"`
	LastModifiedDate   time.Time `json:"lastModifiedDate"`
}

// UIComponent represents a registered UI component
type UIComponent struct {
	ID            string    `json:"id"`
	Name          string    `json:"name"`
	Type          string    `json:"type"` // page, widget, etc.
	IsEmbeddable  bool      `json:"isEmbeddable"`
	Description   *string   `json:"description,omitempty"`
	ComponentPath *string   `json:"componentPath,omitempty"`
	CreatedDate   time.Time `json:"createdDate,omitempty"`
	LastModified  time.Time `json:"lastModifiedDate,omitempty"`
}

// ApprovalPageLayout represents approval page layout configuration for customizing approval response pages
type ApprovalPageLayout struct {
	ID                string              `json:"id"`
	ObjectAPIName     string              `json:"objectApiName"`
	LayoutName        string              `json:"layoutName"`
	Type              string              `json:"type,omitempty"` // approval_response, approval_detail, etc.
	IsDefault         bool                `json:"isDefault,omitempty"`
	IsDeleted         bool                `json:"isDeleted,omitempty"`
	Config            interface{}         `json:"config"` // Parsed layout configuration
	CompactLayout     []string            `json:"compactLayout,omitempty"`
	Sections          []PageSection       `json:"sections,omitempty"`
	RelatedLists      []RelatedListConfig `json:"relatedLists,omitempty"`
	HeaderActions     []ActionConfig      `json:"headerActions,omitempty"`
	QuickActions      []ActionConfig      `json:"quickActions,omitempty"`
	IsCustomized      bool                `json:"isCustomized,omitempty"`      // DEPRECATED: use Source
	LayoutVersion     int                 `json:"layoutVersion,omitempty"`     // DEPRECATED: use GenerationVersion
	Source            string              `json:"source,omitempty"`            // auto_generated, admin_created, cloned, curated
	GenerationVersion int                 `json:"generationVersion,omitempty"` // Algorithm version (only for Source=auto_generated)
	CreatedDate       time.Time           `json:"createdDate,omitempty"`
	LastModifiedDate  time.Time           `json:"lastModifiedDate,omitempty"`
}
