package controllers

import (
	"fmt"
	"strings"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

// QueryHelper provides query parameter parsing and filtering utilities
type QueryHelper struct{}

// SortParams represents sorting parameters
type SortParams struct {
	Field string
	Order string // "asc" or "desc"
}

// FilterParams represents generic filter parameters
type FilterParams map[string]interface{}

// NewQueryHelper creates a new QueryHelper instance
func NewQueryHelper() *QueryHelper {
	return &QueryHelper{}
}

// GetSortParams extracts sort parameters from the request
// Expects: ?sort=field:order (e.g., ?sort=created_at:desc)
func (qh *QueryHelper) GetSortParams(c *gin.Context, defaultField, defaultOrder string) SortParams {
	sortQuery := c.Query("sort")
	if sortQuery == "" {
		return SortParams{
			Field: defaultField,
			Order: defaultOrder,
		}
	}

	parts := strings.Split(sortQuery, ":")
	field := parts[0]
	order := defaultOrder

	if len(parts) > 1 {
		order = strings.ToLower(parts[1])
		if order != "asc" && order != "desc" {
			order = defaultOrder
		}
	}

	return SortParams{
		Field: field,
		Order: order,
	}
}

// ApplySort applies sorting to a GORM query
func (qh *QueryHelper) ApplySort(db *gorm.DB, params SortParams) *gorm.DB {
	if params.Field != "" {
		return db.Order(params.Field + " " + params.Order)
	}
	return db
}

// ApplySortFromContext extracts sort params from context and applies them
func (qh *QueryHelper) ApplySortFromContext(c *gin.Context, db *gorm.DB, defaultField, defaultOrder string) *gorm.DB {
	params := qh.GetSortParams(c, defaultField, defaultOrder)
	return qh.ApplySort(db, params)
}

// GetSearchQuery extracts search query from request
// Expects: ?search=term or ?q=term
func (qh *QueryHelper) GetSearchQuery(c *gin.Context) string {
	search := c.Query("search")
	if search == "" {
		search = c.Query("q")
	}
	return strings.TrimSpace(search)
}

// ApplySearch applies search to specified fields using LIKE
func (qh *QueryHelper) ApplySearch(db *gorm.DB, searchTerm string, fields ...string) *gorm.DB {
	if searchTerm == "" || len(fields) == 0 {
		return db
	}

	searchPattern := "%" + searchTerm + "%"
	query := db

	// Build OR conditions for each field
	for i, field := range fields {
		if i == 0 {
			query = query.Where(field+" LIKE ?", searchPattern)
		} else {
			query = query.Or(field+" LIKE ?", searchPattern)
		}
	}

	return query
}

// ApplySearchFromContext extracts search query and applies it
func (qh *QueryHelper) ApplySearchFromContext(c *gin.Context, db *gorm.DB, fields ...string) *gorm.DB {
	searchTerm := qh.GetSearchQuery(c)
	return qh.ApplySearch(db, searchTerm, fields...)
}

// GetBoolQuery extracts a boolean query parameter
func (qh *QueryHelper) GetBoolQuery(c *gin.Context, key string) *bool {
	value := c.Query(key)
	if value == "" {
		return nil
	}

	boolValue := strings.ToLower(value) == "true" || value == "1"
	return &boolValue
}

// ApplyBoolFilter applies a boolean filter if the parameter exists
func (qh *QueryHelper) ApplyBoolFilter(db *gorm.DB, c *gin.Context, paramKey, dbField string) *gorm.DB {
	value := qh.GetBoolQuery(c, paramKey)
	if value != nil {
		return db.Where(dbField+" = ?", *value)
	}
	return db
}

// GetIDsFromQuery extracts comma-separated IDs from query parameter
// Expects: ?ids=1,2,3,4
func (qh *QueryHelper) GetIDsFromQuery(c *gin.Context, key string) []uint {
	idsStr := c.Query(key)
	if idsStr == "" {
		return nil
	}

	parts := strings.Split(idsStr, ",")
	ids := make([]uint, 0, len(parts))

	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}
		
		// Parse as uint
		var id uint
		if _, err := fmt.Sscanf(part, "%d", &id); err == nil {
			ids = append(ids, id)
		}
	}

	return ids
}

// ApplyIDsFilter applies IN filter for IDs
func (qh *QueryHelper) ApplyIDsFilter(db *gorm.DB, c *gin.Context, paramKey, dbField string) *gorm.DB {
	ids := qh.GetIDsFromQuery(c, paramKey)
	if len(ids) > 0 {
		return db.Where(dbField+" IN ?", ids)
	}
	return db
}

// GetDateRange extracts date range from query parameters
// Expects: ?from=2024-01-01&to=2024-12-31
func (qh *QueryHelper) GetDateRange(c *gin.Context) (from, to string) {
	from = c.Query("from")
	to = c.Query("to")
	return
}

// ApplyDateRangeFilter applies date range filter
func (qh *QueryHelper) ApplyDateRangeFilter(db *gorm.DB, c *gin.Context, dbField string) *gorm.DB {
	from, to := qh.GetDateRange(c)
	
	if from != "" {
		db = db.Where(dbField+" >= ?", from)
	}
	if to != "" {
		db = db.Where(dbField+" <= ?", to)
	}
	
	return db
}

// BuildQueryChain combines multiple query operations
func (qh *QueryHelper) BuildQueryChain(c *gin.Context, db *gorm.DB) *QueryChainBuilder {
	return &QueryChainBuilder{
		ctx:   c,
		query: db,
		qh:    qh,
	}
}

// QueryChainBuilder provides a fluent interface for building queries
type QueryChainBuilder struct {
	ctx   *gin.Context
	query *gorm.DB
	qh    *QueryHelper
}

// WithSort adds sorting
func (qcb *QueryChainBuilder) WithSort(defaultField, defaultOrder string) *QueryChainBuilder {
	qcb.query = qcb.qh.ApplySortFromContext(qcb.ctx, qcb.query, defaultField, defaultOrder)
	return qcb
}

// WithSearch adds search across fields
func (qcb *QueryChainBuilder) WithSearch(fields ...string) *QueryChainBuilder {
	qcb.query = qcb.qh.ApplySearchFromContext(qcb.ctx, qcb.query, fields...)
	return qcb
}

// WithBoolFilter adds a boolean filter
func (qcb *QueryChainBuilder) WithBoolFilter(paramKey, dbField string) *QueryChainBuilder {
	qcb.query = qcb.qh.ApplyBoolFilter(qcb.query, qcb.ctx, paramKey, dbField)
	return qcb
}

// WithIDsFilter adds an IDs filter
func (qcb *QueryChainBuilder) WithIDsFilter(paramKey, dbField string) *QueryChainBuilder {
	qcb.query = qcb.qh.ApplyIDsFilter(qcb.query, qcb.ctx, paramKey, dbField)
	return qcb
}

// WithDateRange adds date range filter
func (qcb *QueryChainBuilder) WithDateRange(dbField string) *QueryChainBuilder {
	qcb.query = qcb.qh.ApplyDateRangeFilter(qcb.query, qcb.ctx, dbField)
	return qcb
}

// Build returns the final query
func (qcb *QueryChainBuilder) Build() *gorm.DB {
	return qcb.query
}

// Global QueryHelper instance for convenience
var QueryParser = NewQueryHelper()
