package rest

import (
	"strings"

	"github.com/gin-gonic/gin"
	appErrors "github.com/nexuscrm/backend/pkg/errors"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

// --- Field Handlers ---

// CreateField godoc
// @Summary      Create Field
// @Description  Add a new field to an object.
// @Tags         metadata
// @Accept       json
// @Produce      json
// @Param        apiName path string true "Object API Name"
// @Param        field body models.FieldMetadata true "Field Definition"
// @Success      201  {object}  models.FieldMetadata
// @Failure      400  {object}  map[string]interface{}
// @Router       /metadata/objects/{apiName}/fields [post]
// @Security     BearerAuth
func (h *MetadataHandler) CreateField(c *gin.Context) {
	// requireSystemAdmin handled by middleware

	objectAPIName := c.Param("apiName")

	// Tooling API wrapper to capture object_api_name from body
	type CreateFieldRequest struct {
		models.FieldMetadata
		ObjectAPIName string `json:"object_api_name"`
	}
	var req CreateFieldRequest

	if err := c.ShouldBindJSON(&req); err != nil {
		RespondAppError(c, appErrors.NewValidationError("body", err.Error()))
		return
	}

	field := req.FieldMetadata
	if objectAPIName == "" {
		objectAPIName = req.ObjectAPIName
	}

	if objectAPIName == "" {
		RespondAppError(c, appErrors.NewValidationError("object_api_name", "Object API Name is required"))
		return
	}

	if field.APIName == "" || field.Label == "" {
		RespondAppError(c, appErrors.NewValidationError("api_name", "API Name and Label are required"))
		return
	}

	// Validate field type specific requirements
	switch field.Type {
	case constants.FieldTypePicklist:
		if len(field.Options) == 0 {
			RespondAppError(c, appErrors.NewValidationError("options", "Picklist fields require at least one option"))
			return
		}
	case constants.FieldTypeReference:
		if len(field.ReferenceTo) == 0 {
			RespondAppError(c, appErrors.NewValidationError("reference_to", "Lookup fields require a referenced object"))
			return
		}
	}

	if err := h.svc.Metadata.CreateField(c.Request.Context(), objectAPIName, &field); err != nil {
		RespondAppError(c, err)
		return
	}
	if err := finalizeCreatedFields(c.Request.Context(), h.svc, objectAPIName, []*models.FieldMetadata{&field}); err != nil {
		RespondAppError(c, err)
		return
	}
	c.JSON(201, field)
}

// CreateCustomField handles the Salesforce Tooling API style POST /tooling/sobjects/CustomField.
// It adapts the Tooling API payload to internal FieldMetadata and delegates to the standard CreateField logic.
func (h *MetadataHandler) CreateCustomField(c *gin.Context) {
	// Tooling API payload structure
	type ToolingMetadata struct {
		Label             string  `json:"label"`
		Type              string  `json:"type"`
		Required          bool    `json:"required"`
		Unique            bool    `json:"unique"`
		Description       string  `json:"description"`
		Length            *int    `json:"length"`
		Precision         *int    `json:"precision"`
		Scale             *int    `json:"scale"`
		DefaultValue      *string `json:"defaultValue"`
		InlineHelpText    *string `json:"inlineHelpText"`
		ReferenceTo       *string `json:"referenceTo"`
		RelationshipName  *string `json:"relationshipName"`
		CalculatedFormula *string `json:"calculatedFormula"`
		FormulaMode       *string `json:"formulaMode"`
		ReturnType        *string `json:"returnType"`
		ExternalId        bool    `json:"externalId"`
	}
	type ToolingPayload struct {
		FullName      string          `json:"FullName"` // "Account.MyField__c"
		Metadata      ToolingMetadata `json:"Metadata"`
		TableEnumOrId string          `json:"TableEnumOrId"` // "Account"
	}

	var payload ToolingPayload
	if err := c.ShouldBindJSON(&payload); err != nil {
		RespondAppError(c, appErrors.NewValidationError("body", err.Error()))
		return
	}

	// Extract object and field names from FullName ("Account.MyField__c")
	objectAPIName := payload.TableEnumOrId
	fieldAPIName := ""
	if parts := strings.SplitN(payload.FullName, ".", 2); len(parts) == 2 {
		fieldAPIName = parts[1]
		if objectAPIName == "" {
			objectAPIName = parts[0]
		}
	}
	if objectAPIName == "" || fieldAPIName == "" {
		RespondAppError(c, appErrors.NewValidationError("FullName", "FullName must be in format Object.FieldName__c"))
		return
	}

	// Map Salesforce field types to internal types
	sfTypeMap := map[string]constants.SchemaFieldType{
		"Text":                constants.FieldTypeString,
		"LongTextArea":        constants.FieldTypeTextarea,
		"Html":                constants.FieldTypeRichtextarea,
		"Number":              constants.FieldTypeDouble,
		"Currency":            constants.FieldTypeCurrency,
		"Percent":             constants.FieldTypePercent,
		"Date":                constants.FieldTypeDate,
		"DateTime":            constants.FieldTypeDatetime,
		"Checkbox":            constants.FieldTypeBoolean,
		"Email":               constants.FieldTypeEmail,
		"Phone":               constants.FieldTypePhone,
		"Url":                 constants.FieldTypeUrl,
		"Picklist":            constants.FieldTypePicklist,
		"MultiselectPicklist": constants.FieldTypeMultiPicklist,
		"Lookup":              constants.FieldTypeReference,
	}

	fieldType, ok := sfTypeMap[payload.Metadata.Type]
	if !ok {
		fieldType = constants.FieldTypeString
	}

	// For formula fields, the Tooling type is the display type; actual type is "formula"
	isFormula := payload.Metadata.CalculatedFormula != nil && *payload.Metadata.CalculatedFormula != ""
	if isFormula {
		fieldType = constants.FieldTypeFormula
	}

	// Build FieldMetadata
	field := models.FieldMetadata{
		APIName:  fieldAPIName,
		Label:    payload.Metadata.Label,
		Type:     fieldType,
		Required: payload.Metadata.Required,
		IsUnique: payload.Metadata.Unique,
		HelpText: payload.Metadata.InlineHelpText,
	}

	if payload.Metadata.DefaultValue != nil {
		field.DefaultValue = payload.Metadata.DefaultValue
	}

	if isFormula {
		field.Formula = payload.Metadata.CalculatedFormula
		if payload.Metadata.FormulaMode != nil {
			field.FormulaMode = payload.Metadata.FormulaMode
		} else {
			mode := "active"
			field.FormulaMode = &mode
		}
		if payload.Metadata.ReturnType != nil {
			rt := constants.SchemaFieldType(strings.ToLower(*payload.Metadata.ReturnType))
			field.ReturnType = &rt
		}
	}

	if payload.Metadata.ReferenceTo != nil && *payload.Metadata.ReferenceTo != "" {
		field.ReferenceTo = []string{*payload.Metadata.ReferenceTo}
	}

	// Delegate to the service
	if err := h.svc.Metadata.CreateField(c.Request.Context(), objectAPIName, &field); err != nil {
		RespondAppError(c, err)
		return
	}
	if err := finalizeCreatedFields(c.Request.Context(), h.svc, objectAPIName, []*models.FieldMetadata{&field}); err != nil {
		RespondAppError(c, err)
		return
	}

	// Return SF Tooling API style response
	c.JSON(201, gin.H{
		"id":       field.ID,
		"success":  true,
		"fullName": payload.FullName,
	})
}

// UpdateField godoc
// @Summary      Update Field
// @Description  Update an existing field definition.
// @Tags         metadata
// @Accept       json
// @Produce      json
// @Param        apiName path string true "Object API Name"
// @Param        fieldApiName path string true "Field API Name"
// @Param        updates body models.FieldMetadata true "Field Updates"
// @Success      200  {object}  models.FieldMetadata
// @Failure      400  {object}  map[string]interface{}
// @Router       /metadata/objects/{apiName}/fields/{fieldApiName} [patch]
// @Security     BearerAuth
func (h *MetadataHandler) UpdateField(c *gin.Context) {
	// requireSystemAdmin handled by middleware

	objectAPIName := strings.ToLower(c.Param("apiName"))
	fieldAPIName := c.Param("fieldApiName")
	var updates models.FieldMetadata

	if err := c.ShouldBindJSON(&updates); err != nil {
		RespondAppError(c, appErrors.NewValidationError("body", err.Error()))
		return
	}

	if err := h.svc.Metadata.UpdateField(c.Request.Context(), objectAPIName, fieldAPIName, &updates); err != nil {
		RespondAppError(c, err)
		return
	}

	c.JSON(200, updates)
}

// DeleteField godoc
// @Summary      Delete Field
// @Description  Delete a field and its data.
// @Tags         metadata
// @Accept       json
// @Produce      json
// @Param        apiName path string true "Object API Name"
// @Param        fieldApiName path string true "Field API Name"
// @Success      204  "No Content"
// @Failure      400  {object}  map[string]interface{}
// @Router       /metadata/objects/{apiName}/fields/{fieldApiName} [delete]
// @Security     BearerAuth
func (h *MetadataHandler) DeleteField(c *gin.Context) {
	// requireSystemAdmin handled by middleware

	objectAPIName := strings.ToLower(c.Param("apiName"))
	fieldAPIName := c.Param("fieldApiName")

	if err := h.svc.Metadata.DeleteField(c.Request.Context(), objectAPIName, fieldAPIName); err != nil {
		RespondAppError(c, err)
		return
	}

	c.Status(204)
}

// GetFieldTypes godoc
// @Summary      Get Field Types
// @Description  List all available field types.
// @Tags         metadata
// @Accept       json
// @Produce      json
// @Success      200  {object}  map[string]interface{} "Wrapped list of field types"
// @Router       /metadata/fieldtypes [get]
// @Security     BearerAuth
func (h *MetadataHandler) GetFieldTypes(c *gin.Context) {
	c.JSON(200, map[string]interface{}{"fieldTypes": GetAllFieldTypes()})
}

// BatchCreateFields godoc
// @Summary      Batch Create Fields
// @Description  Create multiple fields for an object in one transaction.
// @Tags         metadata
// @Accept       json
// @Produce      json
// @Param        apiName path string true "Object API Name"
// @Param        fields body []models.FieldMetadata true "List of Field Definitions"
// @Success      201  {object}  map[string]interface{} "Wrapped list of created fields"
// @Failure      400  {object}  map[string]interface{}
// @Router       /metadata/objects/{apiName}/fields/batch [post]
// @Security     BearerAuth
func (h *MetadataHandler) BatchCreateFields(c *gin.Context) {
	// requireSystemAdmin handled by middleware

	objectAPIName := strings.ToLower(c.Param("apiName"))
	var fields []models.FieldMetadata

	if err := c.ShouldBindJSON(&fields); err != nil {
		RespondAppError(c, appErrors.NewValidationError("body", err.Error()))
		return
	}

	createdFields, err := h.svc.Metadata.BatchCreateFields(c.Request.Context(), objectAPIName, fields)
	if err != nil {
		RespondAppError(c, err)
		return
	}

	if err := finalizeCreatedFields(c.Request.Context(), h.svc, objectAPIName, createdFields); err != nil {
		RespondAppError(c, err)
		return
	}

	c.JSON(201, map[string]interface{}{"fields": fields})
}
