package dialectsfcrm

import (
	"strings"

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

type toolingCustomFieldPicklistValue struct {
	FullName string `json:"fullName"`
	Label    string `json:"label"`
	Default  bool   `json:"default"`
}

type toolingCustomFieldValueSetDefinition struct {
	Sorted bool                              `json:"sorted"`
	Value  []toolingCustomFieldPicklistValue `json:"value"`
}

type toolingCustomFieldPicklist struct {
	PicklistValues []toolingCustomFieldPicklistValue `json:"picklistValues"`
	Sorted         bool                              `json:"sorted"`
}

type toolingCustomFieldMetadata struct {
	Label                 string                      `json:"label"`
	Type                  string                      `json:"type"`
	Required              bool                        `json:"required"`
	IsUnique              bool                        `json:"unique"`
	Description           string                      `json:"description"`
	InlineHelpText        *string                     `json:"inlineHelpText"`
	DefaultValue          *string                     `json:"defaultValue"`
	Length                *int                        `json:"length"`
	Precision             *int                        `json:"precision"`
	Scale                 *int                        `json:"scale"`
	CalculatedFormula     *string                     `json:"calculatedFormula"`
	Formula               *string                     `json:"formula"`
	FormulaMode           *string                     `json:"formulaMode"`
	FormulaStorageMode    *string                     `json:"formulaStorageMode"`
	ReturnType            *string                     `json:"returnType"`
	ReferenceTo           []string                    `json:"referenceTo"`
	RelationshipName      *string                     `json:"relationshipName"`
	ChildRelationshipName *string                     `json:"childRelationshipName"`
	Picklist              *toolingCustomFieldPicklist `json:"picklist"`
	ValueSet              *struct {
		ValueSetDefinition *toolingCustomFieldValueSetDefinition `json:"valueSetDefinition"`
	} `json:"valueSet"`
}

type toolingCustomFieldRequest struct {
	FullName              string                      `json:"FullName"`
	TableEnumOrId         string                      `json:"TableEnumOrId"`
	ObjectAPIName         string                      `json:"object_api_name"`
	Name                  string                      `json:"name"`
	Label                 string                      `json:"label"`
	Type                  string                      `json:"type"`
	Required              bool                        `json:"required"`
	IsUnique              bool                        `json:"unique"`
	Description           string                      `json:"description"`
	InlineHelpText        *string                     `json:"inlineHelpText"`
	DefaultValue          *string                     `json:"defaultValue"`
	Length                *int                        `json:"length"`
	Precision             *int                        `json:"precision"`
	Scale                 *int                        `json:"scale"`
	CalculatedFormula     *string                     `json:"calculatedFormula"`
	Formula               *string                     `json:"formula"`
	FormulaMode           *string                     `json:"formulaMode"`
	FormulaStorageMode    *string                     `json:"formulaStorageMode"`
	ReturnType            *string                     `json:"returnType"`
	ReferenceTo           []string                    `json:"referenceTo"`
	RelationshipName      *string                     `json:"relationshipName"`
	ChildRelationshipName *string                     `json:"childRelationshipName"`
	Picklist              *toolingCustomFieldPicklist `json:"picklist"`
	ValueSet              *struct {
		ValueSetDefinition *toolingCustomFieldValueSetDefinition `json:"valueSetDefinition"`
	} `json:"valueSet"`
	Metadata toolingCustomFieldMetadata `json:"Metadata"`
}

func normalizeToolingCustomFieldType(fieldType string) models.FieldType {
	trimmed := strings.TrimSpace(fieldType)
	if trimmed == "" {
		return ""
	}
	switch strings.ToLower(trimmed) {
	case "text", "string":
		return constants.FieldTypeString
	case "longtextarea", "textarea":
		return constants.FieldTypeTextarea
	case "html", "richtext":
		return models.FieldType("richtext")
	case "richtextarea":
		return constants.FieldTypeRichtextarea
	case "number", "double":
		return constants.FieldTypeDouble
	case "currency":
		return constants.FieldTypeCurrency
	case "percent":
		return constants.FieldTypePercent
	case "date":
		return constants.FieldTypeDate
	case "datetime":
		return constants.FieldTypeDatetime
	case "time":
		return models.FieldType("time")
	case "checkbox", "boolean":
		return constants.FieldTypeBoolean
	case "email":
		return constants.FieldTypeEmail
	case "phone":
		return constants.FieldTypePhone
	case "url":
		return constants.FieldTypeUrl
	case "picklist":
		return constants.FieldTypePicklist
	case "multiselectpicklist", "multipicklist":
		return constants.FieldTypeMultiPicklist
	case "lookup", "reference":
		return constants.FieldTypeReference
	case "formula":
		return constants.FieldTypeFormula
	default:
		return models.FieldType(trimmed)
	}
}

func normalizeToolingCustomFieldRequest(toolingReq toolingCustomFieldRequest) (string, models.FieldMetadata, error) {
	objectAPIName := toolingReq.TableEnumOrId
	if objectAPIName == "" {
		objectAPIName = toolingReq.ObjectAPIName
	}
	fieldAPIName := toolingReq.Name
	if parts := strings.SplitN(toolingReq.FullName, ".", 2); len(parts) == 2 {
		if objectAPIName == "" {
			objectAPIName = parts[0]
		}
		fieldAPIName = parts[1]
	} else if toolingReq.FullName != "" && fieldAPIName == "" {
		fieldAPIName = toolingReq.FullName
	}
	if objectAPIName == "" {
		return "", models.FieldMetadata{}, &contract.MetadataAuthoringError{
			Kind:    contract.MetadataAuthoringErrorValidation,
			Field:   "TableEnumOrId",
			Message: "validation error on field 'TableEnumOrId': TableEnumOrId or object_api_name is required",
		}
	}
	if fieldAPIName == "" {
		return "", models.FieldMetadata{}, &contract.MetadataAuthoringError{
			Kind:    contract.MetadataAuthoringErrorValidation,
			Field:   "FullName",
			Message: "validation error on field 'FullName': FullName or name is required",
		}
	}
	metadata := mergedToolingCustomFieldMetadata(toolingReq)
	internalType := normalizeToolingCustomFieldType(metadata.Type)
	if internalType == "" {
		internalType = models.FieldType(metadata.Type)
	}
	formulaExpr := firstStringPtr(metadata.CalculatedFormula, metadata.Formula)
	formulaIntent := internalType == constants.FieldTypeFormula ||
		metadata.CalculatedFormula != nil ||
		metadata.Formula != nil ||
		metadata.FormulaMode != nil ||
		metadata.FormulaStorageMode != nil ||
		metadata.ReturnType != nil

	field := models.FieldMetadata{
		APIName:  fieldAPIName,
		Label:    metadata.Label,
		Type:     internalType,
		Required: metadata.Required,
		IsUnique: metadata.IsUnique,
		HelpText: metadata.InlineHelpText,
	}
	if field.Label == "" {
		field.Label = fieldAPIName
	}
	if metadata.DefaultValue != nil {
		field.DefaultValue = metadata.DefaultValue
	}
	if metadata.Length != nil {
		field.MaxLength = metadata.Length
	}
	if metadata.Precision != nil {
		field.Precision = metadata.Precision
	}
	if metadata.Scale != nil {
		field.Scale = metadata.Scale
	}
	if len(metadata.ReferenceTo) > 0 {
		field.ReferenceTo = metadata.ReferenceTo
	}
	if metadata.RelationshipName != nil {
		field.RelationshipName = metadata.RelationshipName
	}
	if metadata.ChildRelationshipName != nil {
		field.ChildRelationshipName = metadata.ChildRelationshipName
	}
	if formulaIntent && formulaExpr != nil {
		field.Formula = formulaExpr
	}
	if formulaIntent {
		field.Type = constants.FieldTypeFormula
		mode := "active"
		if metadata.FormulaMode != nil && strings.TrimSpace(*metadata.FormulaMode) != "" {
			mode = strings.TrimSpace(*metadata.FormulaMode)
		}
		field.FormulaMode = &mode
		if metadata.FormulaStorageMode != nil && strings.TrimSpace(*metadata.FormulaStorageMode) != "" {
			storageMode := strings.TrimSpace(*metadata.FormulaStorageMode)
			field.FormulaStorageMode = &storageMode
		}
		if metadata.ReturnType != nil && strings.TrimSpace(*metadata.ReturnType) != "" {
			returnType := normalizeToolingCustomFieldType(*metadata.ReturnType)
			field.ReturnType = &returnType
		} else if formulaExpr != nil && strings.TrimSpace(*formulaExpr) != "" {
			return "", models.FieldMetadata{}, &contract.MetadataAuthoringError{
				Kind:    contract.MetadataAuthoringErrorValidation,
				Field:   "returnType",
				Message: "validation error on field 'returnType': formula fields require a non-empty returnType",
			}
		}
	}
	if metadata.ValueSet != nil && metadata.ValueSet.ValueSetDefinition != nil {
		for _, v := range metadata.ValueSet.ValueSetDefinition.Value {
			field.Options = append(field.Options, models.PicklistOption{Value: v.FullName, Label: v.FullName})
		}
	} else if metadata.Picklist != nil {
		for _, v := range metadata.Picklist.PicklistValues {
			field.Options = append(field.Options, models.PicklistOption{Value: v.FullName, Label: v.FullName})
		}
	}
	return objectAPIName, field, nil
}

func firstStringPtr(values ...*string) *string {
	for _, value := range values {
		if value != nil {
			return value
		}
	}
	return nil
}

func mergedToolingCustomFieldMetadata(req toolingCustomFieldRequest) toolingCustomFieldMetadata {
	metadata := req.Metadata
	if metadata.Label == "" {
		metadata.Label = req.Label
	}
	if metadata.Type == "" {
		metadata.Type = req.Type
	}
	if !metadata.Required {
		metadata.Required = req.Required
	}
	if !metadata.IsUnique {
		metadata.IsUnique = req.IsUnique
	}
	if metadata.Description == "" {
		metadata.Description = req.Description
	}
	if metadata.InlineHelpText == nil {
		metadata.InlineHelpText = req.InlineHelpText
	}
	if metadata.DefaultValue == nil {
		metadata.DefaultValue = req.DefaultValue
	}
	if metadata.Length == nil {
		metadata.Length = req.Length
	}
	if metadata.Precision == nil {
		metadata.Precision = req.Precision
	}
	if metadata.Scale == nil {
		metadata.Scale = req.Scale
	}
	if metadata.CalculatedFormula == nil {
		metadata.CalculatedFormula = req.CalculatedFormula
	}
	if metadata.Formula == nil {
		metadata.Formula = req.Formula
	}
	if metadata.FormulaMode == nil {
		metadata.FormulaMode = req.FormulaMode
	}
	if metadata.FormulaStorageMode == nil {
		metadata.FormulaStorageMode = req.FormulaStorageMode
	}
	if metadata.ReturnType == nil {
		metadata.ReturnType = req.ReturnType
	}
	if len(metadata.ReferenceTo) == 0 {
		metadata.ReferenceTo = req.ReferenceTo
	}
	if metadata.RelationshipName == nil {
		metadata.RelationshipName = req.RelationshipName
	}
	if metadata.ChildRelationshipName == nil {
		metadata.ChildRelationshipName = req.ChildRelationshipName
	}
	if metadata.Picklist == nil {
		metadata.Picklist = req.Picklist
	}
	if metadata.ValueSet == nil {
		metadata.ValueSet = req.ValueSet
	}
	return metadata
}
