package rest

import (
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/nexuscrm/backend/internal/application/services"
	"github.com/nexuscrm/backend/pkg/apierr"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

const (
	// DefaultLayoutLimitRows is the default number of rows for search results
	DefaultLayoutLimitRows = 25
	// MaxSearchColumns is the maximum number of columns in search layout
	MaxSearchColumns = 6
)

// SearchLayoutHandler handles /search/layout endpoint
type SearchLayoutHandler struct {
	svcMgr *services.ServiceManager
}

// NewSearchLayoutHandler creates a new SearchLayoutHandler
func NewSearchLayoutHandler(svcMgr *services.ServiceManager) *SearchLayoutHandler {
	return &SearchLayoutHandler{svcMgr: svcMgr}
}

// SearchColumn represents a column in search results (Salesforce-compatible)
type SearchColumn struct {
	Field  string      `json:"field"`
	Format interface{} `json:"format"` // null for non-date fields
	Label  string      `json:"label"`
	Name   string      `json:"name"`
}

// SearchLayoutResult represents the layout for one object (Salesforce-compatible)
type SearchLayoutResult struct {
	Label         string         `json:"label"`
	LimitRows     int            `json:"limitRows"`
	ObjectType    string         `json:"objectType"`
	SearchColumns []SearchColumn `json:"searchColumns"`
}

// GetLayout handles GET /services/data/vXX.X/search/layout?q=Account,Contact
// Returns the search result layout configuration for each object
// Salesforce-compatible response format
//
// @Summary      Get Search Result Layouts
// @Description  Returns the search result layout configuration for each object specified
// @Tags         search
// @Produce      json
// @Param        q query string true "Comma-separated list of object API names"
// @Success      200  {array}  SearchLayoutResult
// @Failure      400  {object}  map[string]interface{}
// @Failure      401  {object}  map[string]interface{}
// @Router       /search/layout [get]
// @Security     BearerAuth
func (h *SearchLayoutHandler) GetLayout(c *gin.Context) {
	MustGetUser(c)

	objectsParam := c.Query("q")
	if objectsParam == "" {
		c.JSON(http.StatusBadRequest, apierr.SFErrorResponse(apierr.SFCodeMissingQuery, "Query parameter 'q' is required"))
		return
	}

	objects := strings.Split(objectsParam, ",")
	result := make([]SearchLayoutResult, 0, len(objects))

	for _, objName := range objects {
		objName = strings.TrimSpace(objName)
		if objName == "" {
			continue
		}

		// Get schema for this object
		schema := h.svcMgr.Metadata.GetSchema(c.Request.Context(), objName)
		if schema == nil {
			c.JSON(http.StatusNotFound, apierr.SFErrorResponse(apierr.SFCodeNotFound, "Object not found: "+objName))
			return
		}

		columns := h.buildSearchColumns(schema)
		result = append(result, SearchLayoutResult{
			Label:         "Search Results",
			LimitRows:     DefaultLayoutLimitRows,
			ObjectType:    schema.APIName,
			SearchColumns: columns,
		})
	}

	c.JSON(http.StatusOK, result)
}

// buildSearchColumns generates search columns from object schema
// Follows Salesforce convention: Name field first, then other important fields
func (h *SearchLayoutHandler) buildSearchColumns(schema *models.ObjectMetadata) []SearchColumn {
	return buildSearchColumns(schema)
}

func buildSearchColumns(schema *models.ObjectMetadata) []SearchColumn {
	columns := make([]SearchColumn, 0)

	// Priority field types for search results
	priorityFields := []string{"Phone", "Email"}

	// 1. Find and add Name field first
	var nameField *models.FieldMetadata
	for i := range schema.Fields {
		if schema.Fields[i].APIName == "Name" {
			nameField = &schema.Fields[i]
			break
		}
	}
	if nameField == nil {
		for i := range schema.Fields {
			if schema.Fields[i].IsNameField {
				nameField = &schema.Fields[i]
				break
			}
		}
	}

	if nameField != nil {
		columns = append(columns, SearchColumn{
			Field:  schema.APIName + "." + nameField.APIName,
			Format: nil,
			Label:  nameField.Label,
			Name:   nameField.APIName,
		})
	}

	// 2. Add other priority fields if they exist
	for _, fieldName := range priorityFields {
		for i := range schema.Fields {
			f := &schema.Fields[i]
			if strings.EqualFold(f.APIName, fieldName) && !f.IsNameField {
				columns = append(columns, SearchColumn{
					Field:  schema.APIName + "." + f.APIName,
					Format: nil,
					Label:  f.Label,
					Name:   f.APIName,
				})
				break
			}
		}
	}

	// 3. Add Owner field if exists
	for i := range schema.Fields {
		f := &schema.Fields[i]
		if f.APIName == "OwnerId" && len(f.ReferenceTo) > 0 && f.ReferenceTo[0] == constants.TableUser {
			columns = append(columns, SearchColumn{
				Field:  "User.Alias",
				Format: nil,
				Label:  schema.Label + " Owner Alias",
				Name:   "Owner.Alias",
			})
			break
		}
	}

	// 4. Add additional text fields up to 6 columns total
	for i := range schema.Fields {
		if len(columns) >= MaxSearchColumns {
			break
		}

		f := &schema.Fields[i]

		// Skip already added fields
		alreadyAdded := false
		for _, col := range columns {
			if col.Name == f.APIName {
				alreadyAdded = true
				break
			}
		}
		if alreadyAdded {
			continue
		}

		// Add string fields that are likely useful for search
		if (f.Type == "string" || f.Type == "VARCHAR(255)") && !f.IsSystem && f.APIName != "Id" {
			columns = append(columns, SearchColumn{
				Field:  schema.APIName + "." + f.APIName,
				Format: nil,
				Label:  f.Label,
				Name:   f.APIName,
			})
		}
	}

	return columns
}
