package metadata

import (
	"strings"

	"github.com/nexuscrm/backend/internal/controlplane/packspec"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/fieldprovenance"
	"github.com/nexuscrm/shared/pkg/models"
)

// ExpandCompoundFieldMembers returns the schema-existing members of a
// compound field, using metadata as the single source of truth.
//
// Resolution order (one fact, one read path):
//
//  1. fieldprovenance.ClassifyCompound — primary classifier, the same one
//     callers across persistence, records, and search use today.
//  2. packspec.CompoundFieldComponents — fallback that reads
//     `compoundFieldName` annotations from the embedded `standard_objects_spec.json`
//     and tenant overlays. Catches Lead's Salutation/FirstName/LastName which
//     fieldprovenance does not classify but every persistence layer expands
//     when assembling a compound write. When the caller hands us an
//     IsNameField surface (e.g. Lead's `LastName`), we resolve through the
//     canonical compound name (`Name`) so packspec finds the components.
//  3. Schema-existence filter — packspec is the SSoT for compound shape but
//     a tenant overlay may not expose every member (e.g. a Contact schema
//     without Salutation). Members not declared on the supplied schema are
//     dropped so consumers don't push non-existent fields into SOQL.
//
// Returns (false, nil) when the field is not compound or no usable members
// are found. Replaces the prior duplicated FirstName/LastName fallbacks in
// `interfaces/rest/search_sosl.go` and `features/analytics/query_service.go`
// (per IANTHEREAL P0 review on PR #1963 / issue #1455).
func ExpandCompoundFieldMembers(schema *models.ObjectMetadata, fieldAPIName string) (bool, []string) {
	if schema == nil || strings.TrimSpace(fieldAPIName) == "" {
		return false, nil
	}

	if isCompound, members := fieldprovenance.ClassifyCompound(schema.APIName, fieldAPIName); isCompound {
		return true, filterMembersToSchema(schema, members)
	}

	compoundName := fieldAPIName
	if !strings.EqualFold(fieldAPIName, constants.FieldName) {
		if field, ok := lookupField(schema, fieldAPIName); ok && field.IsNameField {
			compoundName = constants.FieldName
		}
	}

	candidates := packspec.CompoundFieldComponents(schema.APIName, compoundName)
	members := filterMembersToSchema(schema, candidates)
	if len(members) == 0 {
		return false, nil
	}
	return true, members
}

func filterMembersToSchema(schema *models.ObjectMetadata, candidates []string) []string {
	if schema == nil || len(candidates) == 0 {
		return nil
	}
	out := make([]string, 0, len(candidates))
	for _, m := range candidates {
		if _, ok := lookupField(schema, m); ok {
			out = append(out, m)
		}
	}
	return out
}

func lookupField(schema *models.ObjectMetadata, apiName string) (models.FieldMetadata, bool) {
	if schema == nil {
		return models.FieldMetadata{}, false
	}
	for _, field := range schema.Fields {
		if strings.EqualFold(field.APIName, apiName) {
			return field, true
		}
	}
	return models.FieldMetadata{}, false
}
