package metadata

import (
	"context"
	"strings"

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

// CompoundVirtualFieldDeclaration declares a virtual compound field supplied by
// platform or product composition instead of inferred inside the generic
// decorator.
type CompoundVirtualFieldDeclaration struct {
	ObjectAPIName string
	Field         models.FieldMetadata
}

// CompoundVirtualFieldDecorator adds registered virtual compound fields to
// effective schemas. It owns the generic clone/apply mechanics only; field
// membership comes from constructor declarations.
type CompoundVirtualFieldDecorator struct {
	declarations []CompoundVirtualFieldDeclaration
}

func NewCompoundVirtualFieldDecorator(decls ...CompoundVirtualFieldDeclaration) *CompoundVirtualFieldDecorator {
	return &CompoundVirtualFieldDecorator{declarations: cloneCompoundVirtualFieldDeclarations(decls)}
}

// PlatformCompoundVirtualFieldDeclarations returns the platform-floor virtual
// compound fields. This is the explicit owner for auth/user floor shape; the
// generic decorator remains no-op unless these declarations are registered.
func PlatformCompoundVirtualFieldDeclarations() []CompoundVirtualFieldDeclaration {
	returnType := models.FieldType(constants.FieldTypeString)
	return []CompoundVirtualFieldDeclaration{{
		ObjectAPIName: constants.TableUser,
		Field: models.FieldMetadata{
			APIName:      constants.FieldName,
			Label:        "Full Name",
			Type:         constants.FieldTypeFormula,
			ReturnType:   &returnType,
			IsSystem:     true,
			IsNameField:  true,
			Createable:   false,
			Updateable:   false,
			IsVirtual:    true,
			VirtualKind:  constants.VirtualFieldCompound,
			IsCompound:   true,
			ComposedFrom: []string{constants.FieldFirstName, constants.FieldLastName},
		},
	}}
}

// PlatformCompoundVirtualFieldNames returns the platform-owned virtual
// compound field API names that should appear on the effective schema for the
// provided object.
func PlatformCompoundVirtualFieldNames(schema *models.ObjectMetadata) []string {
	fields := compoundVirtualFieldsForSchema(schema, PlatformCompoundVirtualFieldDeclarations())
	if len(fields) == 0 {
		return nil
	}
	names := make([]string, 0, len(fields))
	for _, field := range fields {
		names = append(names, field.APIName)
	}
	return names
}

func (d *CompoundVirtualFieldDecorator) DecorateSchema(_ context.Context, schema *models.ObjectMetadata) (*models.ObjectMetadata, error) {
	if schema == nil {
		return nil, nil
	}
	additions := compoundVirtualFieldsForSchema(schema, d.declarations)
	if len(additions) == 0 {
		return schema, nil
	}
	return models.CloneWithAdditionalFields(schema, additions), nil
}

func compoundVirtualFieldsForSchema(schema *models.ObjectMetadata, decls []CompoundVirtualFieldDeclaration) []models.FieldMetadata {
	if schema == nil || len(decls) == 0 {
		return nil
	}
	out := make([]models.FieldMetadata, 0, len(decls))
	for _, decl := range decls {
		if !strings.EqualFold(strings.TrimSpace(decl.ObjectAPIName), schema.APIName) {
			continue
		}
		field := cloneCompoundVirtualField(decl.Field)
		if strings.TrimSpace(field.APIName) == "" || len(field.ComposedFrom) == 0 {
			continue
		}
		if !compoundMembersExist(schema, field.ComposedFrom) {
			continue
		}
		field.IsVirtual = true
		field.VirtualKind = constants.VirtualFieldCompound
		field.IsCompound = true
		field.Createable = false
		field.Updateable = false
		out = append(out, field)
	}
	return out
}

func compoundMembersExist(schema *models.ObjectMetadata, members []string) bool {
	for _, member := range members {
		if strings.TrimSpace(member) == "" || models.FindField(schema, member) == nil {
			return false
		}
	}
	return true
}

func cloneCompoundVirtualFieldDeclarations(in []CompoundVirtualFieldDeclaration) []CompoundVirtualFieldDeclaration {
	if len(in) == 0 {
		return nil
	}
	out := make([]CompoundVirtualFieldDeclaration, len(in))
	for i := range in {
		out[i] = CompoundVirtualFieldDeclaration{
			ObjectAPIName: in[i].ObjectAPIName,
			Field:         cloneCompoundVirtualField(in[i].Field),
		}
	}
	return out
}

func cloneCompoundVirtualField(in models.FieldMetadata) models.FieldMetadata {
	out := in
	if in.ReturnType != nil {
		rt := *in.ReturnType
		out.ReturnType = &rt
	}
	if len(in.ComposedFrom) > 0 {
		out.ComposedFrom = append([]string(nil), in.ComposedFrom...)
	}
	return out
}
