package constants

import "strings"

// SchemaFieldType represents the type of a field
// These use Salesforce-compatible lowercase naming for maximum SDK compatibility
type SchemaFieldType string

// Salesforce-compatible field types (lowercase as per Salesforce API conventions)
const (
	// Core types
	FieldTypeString    SchemaFieldType = "string"    // Text field
	FieldTypeInt       SchemaFieldType = "int"       // Integer field
	FieldTypeDouble    SchemaFieldType = "double"    // Numeric field
	FieldTypeCurrency  SchemaFieldType = "currency"  // Money field
	FieldTypeDate      SchemaFieldType = "date"      // Date only
	FieldTypeDatetime  SchemaFieldType = "datetime"  // Date + time
	FieldTypeBoolean   SchemaFieldType = "boolean"   // Checkbox
	FieldTypePicklist  SchemaFieldType = "picklist"  // Dropdown
	FieldTypeEmail     SchemaFieldType = "email"     // Email address
	FieldTypePhone     SchemaFieldType = "phone"     // Phone number
	FieldTypeTextarea  SchemaFieldType = "textarea"  // Multi-line text
	FieldTypeUrl       SchemaFieldType = "url"       // Web URL
	FieldTypePercent   SchemaFieldType = "percent"   // Percentage
	FieldTypeReference SchemaFieldType = "reference" // Lookup relationship

	// Extended types
	FieldTypeMasterDetail    SchemaFieldType = "masterdetail"    // Parent-child relationship
	FieldTypeFormula         SchemaFieldType = "formula"         // Calculated field
	FieldTypeRollupSummary   SchemaFieldType = "rollupsummary"   // Aggregate field
	FieldTypeRichtextarea    SchemaFieldType = "richtextarea"    // Rich text / HTML
	FieldTypeAutonumber      SchemaFieldType = "autonumber"      // Auto-increment
	FieldTypeMultiPicklist   SchemaFieldType = "multipicklist"   // Multi-select
	FieldTypeEncryptedString SchemaFieldType = "encryptedstring" // Encrypted text
	FieldTypePassword        SchemaFieldType = "password"        // Password field
	FieldTypeJson            SchemaFieldType = "json"            // JSON data (custom extension)
)

// NormalizeFieldType normalizes field type input to lowercase Salesforce-compatible format.
// This is the canonical function for field type normalization.
func NormalizeFieldType(input string) SchemaFieldType {
	normalized := strings.ToLower(strings.TrimSpace(input))
	switch normalized {
	case "multiselectpicklist":
		return FieldTypeMultiPicklist
	default:
		return SchemaFieldType(normalized)
	}
}

// IsReferenceType checks if the field type represents a relationship
func IsReferenceType(t SchemaFieldType) bool {
	return t == FieldTypeReference || t == FieldTypeMasterDetail
}

// IsMultiPicklistLike reports whether the raw field-type string (as stored in
// _System_Field.Type or carried in CompileContext.FieldTypes) represents a
// multi-select picklist after normalization.
func IsMultiPicklistLike(raw string) bool {
	return NormalizeFieldType(raw) == FieldTypeMultiPicklist
}

// IsDisplayNameFieldRenderableType reports whether a field type can be used as
// an object's display-name source by list/search renderers.
func IsDisplayNameFieldRenderableType(t SchemaFieldType) bool {
	switch NormalizeFieldType(string(t)) {
	case FieldTypeReference,
		FieldTypeMasterDetail,
		FieldTypeString,
		FieldTypeTextarea,
		FieldTypeEmail,
		FieldTypePhone,
		FieldTypeUrl,
		FieldTypeAutonumber:
		return true
	default:
		return false
	}
}

// IsDisplayNameRelationshipChildType reports whether a one-hop relationship
// child can be used as the terminal display-name value. Unlike a direct
// displayNameField reference, a child reference would require another
// relationship traversal to render a label, so only scalar text-like types are
// accepted here.
func IsDisplayNameRelationshipChildType(t SchemaFieldType) bool {
	switch NormalizeFieldType(string(t)) {
	case FieldTypeString,
		FieldTypeTextarea,
		FieldTypeEmail,
		FieldTypePhone,
		FieldTypeUrl,
		FieldTypeAutonumber:
		return true
	default:
		return false
	}
}

// TableCategory defines the category of a table
const (
	TableCategoryStandard = "standard"
	TableCategoryCustom   = "custom"
	TableCategorySystem   = "system"
)

// SharingModel represents object-level sharing model
type SharingModel string

const (
	SharingModelPrivate              SharingModel = "Private"
	SharingModelPublicRead           SharingModel = "PublicRead"
	SharingModelPublicReadWrite      SharingModel = "PublicReadWrite"
	SharingModelControlledByParent   SharingModel = "ControlledByParent"
	SharingModelFolderSharing        SharingModel = "FolderSharing"
	SharingModelFolderContentSharing SharingModel = "FolderContentSharing" // Report/Dashboard: access derived from FolderId's folder visibility
)

// _System_RecordShare.Reason values identify what created a share row so the
// owning subsystem can reconcile exactly its own rows without touching shares
// created by other mechanisms (manual sharing, future owner/team shares).
const (
	// RecordShareReasonApproval tags shares the approval engine grants to
	// pending approvers; the engine inserts and revokes them by this reason.
	RecordShareReasonApproval = "Approval"
)

// DeleteRule represents referential integrity rules
type DeleteRule string

const (
	DeleteRuleRestrict DeleteRule = "Restrict"
	DeleteRuleCascade  DeleteRule = "Cascade"
	DeleteRuleSetNull  DeleteRule = "SetNull"
)

// NormalizeDeleteRule canonicalizes a delete-rule value to the enum constants
// used by metadata/runtime code. It accepts both authored enum casing
// ("Cascade", "SetNull") and physical SQL forms read back from schema metadata
// ("CASCADE", "SET NULL", "NO ACTION"). Unknown values return "" so callers can
// fail closed, usually by treating the rule as Restrict.
func NormalizeDeleteRule(rule DeleteRule) DeleteRule {
	switch strings.ToLower(strings.ReplaceAll(strings.TrimSpace(string(rule)), " ", "")) {
	case "cascade":
		return DeleteRuleCascade
	case "setnull":
		return DeleteRuleSetNull
	case "restrict", "noaction":
		return DeleteRuleRestrict
	default:
		return ""
	}
}

// ObjectCategory defines the category of an object
type ObjectCategory string

const (
	ObjectCategoryCustom ObjectCategory = "Custom"
	ObjectCategorySystem ObjectCategory = "System"
)

// OutboxEventStatus represents the processing status of outbox events
type OutboxEventStatus string

const (
	OutboxStatusPending   OutboxEventStatus = "pending"
	OutboxStatusProcessed OutboxEventStatus = "processed"
	OutboxStatusFailed    OutboxEventStatus = "failed"
)

// ApproverType for Approval Processes
type ApproverType string

const (
	ApproverTypeSelf     ApproverType = "Self"
	ApproverTypeSpecific ApproverType = "Specific"
)

// Navigation Item Types (aligned with frontend NavigationItemType union)
const (
	NavigationTypeObject    = "object"
	NavigationTypePage      = "page"
	NavigationTypeWeb       = "web"
	NavigationTypeDashboard = "dashboard"
)

// List View Defaults
const (
	ListViewDefaultDeveloperName = "RecentlyViewed"
)

// UI Defaults
const (
	LayoutNameDefault       = "Default Layout"
	SectionLabelInformation = "Information"
	SectionLabelSystemInfo  = "System Information"
	SectionLabelAddress     = "Address Information"
	SectionLabelDescription = "Description"
	SectionLabelDetails     = "Additional Details"
)

// Analytics Operations
const (
	AnalyticsOperationGroupBy = "group_by"
	AnalyticsOperationCount   = "count"
	AnalyticsOperationSum     = "sum"
	AnalyticsOperationAvg     = "avg"
)

// FieldSource classifies the provenance of a _System_Field row.
// Introduced by issue #1582 RFC v1.5 PR A3. Single source of truth for every
// writer (pack applier, bootstrap schema, BackfillSource) and every reader
// (ComputeIntrinsic Layer 1d, AssertSourceIntegrity).
const (
	FieldSourceManaged       = "managed"        // declared by system_tables.json
	FieldSourceStandardSpec  = "standard_spec"  // declared by standard_objects_spec.json
	FieldSourceTenantSpec    = "tenant_spec"    // declared by tenant_objects_spec.json
	FieldSourceCustom        = "custom"         // admin-created via CreateField
	FieldSourceBootstrapSeed = "bootstrap_seed" // reserved for future bootstrap-seed path (no writer today)
	FieldSourceDiscovered    = "discovered"     // DEFAULT — physical column without a declaration
)

// KnownFieldSources enumerates every valid FieldSource value. AssertSourceIntegrity
// rejects rows whose Source is outside this set. Keep aligned with the constants above.
var KnownFieldSources = []string{
	FieldSourceManaged,
	FieldSourceStandardSpec,
	FieldSourceTenantSpec,
	FieldSourceCustom,
	FieldSourceBootstrapSeed,
	FieldSourceDiscovered,
}

// FieldOwnerKind is the explicit ownership discriminator for one _System_Field
// fact. IsCustomized remains an override/edit marker; it must not be used as row
// ownership.
const (
	FieldOwnerKindPack         = "pack"
	FieldOwnerKindPackRetained = "pack_retained"
	FieldOwnerKindPackRemoving = "pack_removing"
	FieldOwnerKindAdmin        = "admin"
	FieldOwnerKindRuntime      = "runtime"
)

// FieldWriteProtectionPolicy declares metadata-owned field-write contracts. The
// runtime gate is generic and reads this fact from schema metadata; it must not
// branch on concrete object names.
const (
	// FieldWriteProtectionTrustedOnly rejects caller-supplied values on both
	// create and update unless a trusted platform context owns the write.
	FieldWriteProtectionTrustedOnly = "trusted_only"
	// FieldWriteProtectionAuthorityOnly rejects values supplied through every
	// generic records and RecordRepository write path, including trusted
	// platform security contexts. A dedicated authority-owned persistence
	// method is required to write the field.
	FieldWriteProtectionAuthorityOnly = "authority_only"
	// FieldWriteProtectionImmutableAfterCreate allows a caller to supply the
	// initial value, but rejects the field on every later update. Trusted
	// platform contexts retain the narrowly-scoped migration escape hatch that
	// applies to all write-protection policies.
	FieldWriteProtectionImmutableAfterCreate = "immutable_after_create"
)

// FieldReadProtectionPolicy declares metadata-owned fields whose reads are
// blocked through generic record/query paths. The runtime gate is generic and
// reads this fact from schema metadata; it must not branch on concrete object
// names.
const (
	FieldReadProtectionBlocked = "blocked"
)
