package persistence

import (
	"strings"

	"golang.org/x/text/cases"
	"golang.org/x/text/language"

	"github.com/nexuscrm/backend/internal/domain/schema"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/fieldnormalize"
	"github.com/nexuscrm/shared/pkg/models"
)

func (r *SchemaRepository) buildFieldMetadataFromColumn(col schema.ColumnDefinition) *models.FieldMetadata {
	isSystem := r.IsSystemColumn(col.Name)
	isNameField := strings.EqualFold(col.Name, constants.FieldName) || col.IsNameField

	var field *models.FieldMetadata
	if isSystem {
		field = r.lookupStandardSystemFieldMetadata(col.Name)
	}
	if field == nil {
		field = &models.FieldMetadata{}
	}

	field.APIName = col.Name
	if col.PhysicalName != "" {
		field.PhysicalName = col.PhysicalName
	} else if field.PhysicalName == "" {
		field.PhysicalName = col.Name
	}

	effectiveType := r.mapSQLTypeToLogical(col.Type)
	if col.LogicalType != "" {
		effectiveType = col.LogicalType
		lt := models.FieldType(col.LogicalType)
		field.LogicalType = &lt
	}

	// Preserve the centrally-defined system-field type unless the column explicitly overrides it.
	if field.Type == "" || col.LogicalType != "" || !isSystem {
		field.Type = models.FieldType(effectiveType)
	}

	if col.Label != "" {
		field.Label = col.Label
	} else if field.Label == "" {
		field.Label = deriveFieldLabel(col.Name, string(field.Type))
	}

	field.Required = !col.Nullable && !isSystem
	field.IsUnique = col.Unique
	field.IsSystem = isSystem
	field.IsNameField = field.IsNameField || isNameField

	if len(col.ReferenceTo) > 0 {
		field.ReferenceTo = append([]string(nil), col.ReferenceTo...)
	}
	field.IsPolymorphic = col.IsPolymorphic || len(field.ReferenceTo) > 1
	field.IsMasterDetail = col.IsMasterDetail

	if len(col.Options) > 0 {
		field.Options = col.Options
	}
	if col.RelationshipName != "" {
		rel := col.RelationshipName
		field.RelationshipName = &rel
	}
	// RecordTypeId is a platform-wide lookup invariant for record-typed business
	// objects. Physical schema discovery cannot infer it from FKs because many
	// imported Salesforce tables omit an actual DB-level foreign key, so repair
	// the metadata shape here when no explicit override exists.
	if strings.EqualFold(col.Name, "RecordTypeId") && col.LogicalType == "" {
		field.Type = constants.FieldTypeReference
		if col.Label == "" {
			field.Label = "Record Type"
		}
		if len(field.ReferenceTo) == 0 {
			field.ReferenceTo = []string{"RecordType"}
		}
		if field.RelationshipName == nil || *field.RelationshipName == "" {
			rel := "RecordType"
			field.RelationshipName = &rel
		}
	}
	if col.Default != "" {
		// Strip DDL single-quote wrapping at the boundary so describe /
		// UI see the typed value, not `'Draft'`. Issue #1582 RFC v1.5 PR D.
		def := fieldnormalize.NormalizeDDLDefaultString(col.Default)
		field.DefaultValue = &def
	}
	// Provenance (Source, IsCompound, ComposedFrom) is derived at read
	// time by fieldprovenance.Classify* under RFC v1.6 — no struct-field
	// propagation from ColumnDefinition is needed or correct. Scanner and
	// builder paths both leave these fields zero, preventing the asymmetry
	// where DDL-derived schemas carried compound metadata while DB-loaded
	// schemas did not.
	if col.Formula != "" {
		formula := col.Formula
		field.Formula = &formula
	}
	if col.ReturnType != "" {
		rt := models.FieldType(col.ReturnType)
		field.ReturnType = &rt
	}
	if col.FormulaMode != "" {
		mode := col.FormulaMode
		field.FormulaMode = &mode
	}
	if col.OnDelete != "" {
		dr := models.DeleteRule(col.OnDelete)
		field.DeleteRule = &dr
	}

	return field
}

func (r *SchemaRepository) lookupStandardSystemFieldMetadata(apiName string) *models.FieldMetadata {
	for _, candidate := range r.GetStandardFieldMetadata() {
		if !strings.EqualFold(candidate.APIName, apiName) {
			continue
		}
		cloned := candidate
		return &cloned
	}
	return nil
}

func (r *SchemaRepository) getSystemFieldLabel(logicalName string) string {
	if logicalName == "" {
		return ""
	}
	if field := r.lookupStandardSystemFieldMetadata(logicalName); field != nil && field.Label != "" {
		return field.Label
	}
	return cases.Title(language.English).String(strings.ReplaceAll(logicalName, "_", " "))
}

func deriveFieldLabel(name string, fieldType string) string {
	labelName := name
	if (fieldType == string(constants.FieldTypeReference) || fieldType == string(constants.FieldTypeMasterDetail)) &&
		strings.HasSuffix(labelName, "Id") {
		labelName = strings.TrimSuffix(labelName, "Id")
	}
	labelName = splitCamelCase(labelName)
	labelName = strings.ReplaceAll(labelName, "_", " ")
	return cases.Title(language.English).String(labelName)
}
