package listing

import (
	"strconv"
	"strings"

	"hfb_sys/backend/internal/middleware"
	"hfb_sys/backend/pkg/response"

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

func currentUserID(c *gin.Context) (uint64, bool) {
	value, ok := c.Get(middleware.ContextUserID)
	if !ok {
		return 0, false
	}
	userID, ok := value.(uint64)
	return userID, ok
}

func currentAdminID(c *gin.Context) (uint64, bool) {
	value, ok := c.Get(middleware.ContextAdminID)
	if !ok {
		return 0, false
	}
	adminID, ok := value.(uint64)
	return adminID, ok
}

func parseID(c *gin.Context) (uint64, bool) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil || id == 0 {
		response.BadRequest(c, "ID 不正确")
		return 0, false
	}
	return id, true
}

func parseAdminListQuery(c *gin.Context) (AdminListQuery, bool) {
	var query AdminListQuery
	if raw := c.Query("owner_id"); raw != "" {
		value, err := strconv.ParseUint(raw, 10, 64)
		if err != nil || value == 0 {
			response.BadRequest(c, "号主 ID 不正确")
			return query, false
		}
		query.OwnerID = value
	}
	if raw := c.Query("limit"); raw != "" {
		value, err := strconv.Atoi(raw)
		if err != nil || value <= 0 {
			response.BadRequest(c, "查询条数不正确")
			return query, false
		}
		query.Limit = value
	}
	if raw := c.Query("page"); raw != "" {
		value, err := strconv.Atoi(raw)
		if err != nil || value <= 0 {
			response.BadRequest(c, "页码不正确")
			return query, false
		}
		query.Page = value
	}
	if raw := c.Query("page_size"); raw != "" {
		value, err := strconv.Atoi(raw)
		if err != nil || value <= 0 {
			response.BadRequest(c, "每页条数不正确")
			return query, false
		}
		query.PageSize = value
	}
	query.Keyword = strings.TrimSpace(c.Query("keyword"))
	query.Status = c.Query("status")
	query.ReviewStatus = c.Query("review_status")
	query.Insurance = parseCSVQuery(c.Query("insurance"))
	query.Stamina = parseCSVQuery(c.Query("stamina"))
	query.Load = parseCSVQuery(c.Query("load"))
	query.SkinGroup = parseCSVQuery(c.Query("skin_group"))
	query.SkinName = parseCSVQuery(firstNonEmpty(c.Query("skin_name"), c.Query("skin")))
	query.MinCoin = parseOptionalFloat(c.Query("min_coin"))
	query.MaxCoin = parseOptionalFloat(c.Query("max_coin"))
	query.MinDeposit = parseOptionalFloat(c.Query("min_deposit"))
	query.MaxDeposit = parseOptionalFloat(c.Query("max_deposit"))
	return query, true
}

func parsePublicListQuery(c *gin.Context) PublicListQuery {
	query := PublicListQuery{
		Page:           parsePositiveInt(c.DefaultQuery("page", "1"), 1),
		PageSize:       parsePositiveInt(c.DefaultQuery("page_size", "20"), 20),
		Keyword:        strings.TrimSpace(c.Query("keyword")),
		Sort:           strings.TrimSpace(c.Query("sort")),
		Zone:           strings.TrimSpace(c.Query("zone")),
		Server:         parseCSVQuery(c.Query("server")),
		Region:         parseCSVQuery(c.Query("region")),
		LoginMethod:    parseCSVQuery(firstNonEmpty(c.Query("login_method"), c.Query("login"))),
		Rank:           parseCSVQuery(c.Query("rank")),
		Insurance:      parseCSVQuery(c.Query("insurance")),
		Stamina:        parseCSVQuery(c.Query("stamina")),
		Load:           parseCSVQuery(c.Query("load")),
		SkinGroup:      parseCSVQuery(c.Query("skin_group")),
		SkinName:       parseCSVQuery(firstNonEmpty(c.Query("skin_name"), c.Query("skin"))),
		MinCoin:        parseOptionalFloat(c.Query("min_coin")),
		MaxCoin:        parseOptionalFloat(c.Query("max_coin")),
		MinRatio:       parseOptionalFloat(c.Query("min_ratio")),
		MaxRatio:       parseOptionalFloat(c.Query("max_ratio")),
		MinPrice:       parseOptionalFloat(c.Query("min_price")),
		MaxPrice:       parseOptionalFloat(c.Query("max_price")),
		MinDeposit:     parseOptionalFloat(c.Query("min_deposit")),
		MaxDeposit:     parseOptionalFloat(c.Query("max_deposit")),
		MinTotal:       parseOptionalFloat(c.Query("min_total")),
		MaxTotal:       parseOptionalFloat(c.Query("max_total")),
		MinFireLevel:   parseOptionalFloat(c.Query("min_fire_level")),
		MaxFireLevel:   parseOptionalFloat(c.Query("max_fire_level")),
		MinSecretKD:    parseOptionalFloat(c.Query("min_secret_kd")),
		MaxSecretKD:    parseOptionalFloat(c.Query("max_secret_kd")),
		ResourceRanges: parseResourceRanges(c),
	}
	if query.PageSize > 50 {
		query.PageSize = 50
	}
	return query
}

func parsePositiveInt(value string, fallback int) int {
	parsed, err := strconv.Atoi(strings.TrimSpace(value))
	if err != nil || parsed <= 0 {
		return fallback
	}
	return parsed
}

func parseOptionalFloat(value string) *float64 {
	value = strings.TrimSpace(value)
	if value == "" {
		return nil
	}
	parsed, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return nil
	}
	return &parsed
}

func parseCSVQuery(value string) []string {
	parts := strings.Split(value, ",")
	result := make([]string, 0, len(parts))
	seen := make(map[string]struct{}, len(parts))
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}
		if _, ok := seen[part]; ok {
			continue
		}
		seen[part] = struct{}{}
		result = append(result, part)
	}
	return result
}

func parseResourceRanges(c *gin.Context) map[string]NumberRange {
	ranges := make(map[string]NumberRange)
	for key, values := range c.Request.URL.Query() {
		if !strings.HasPrefix(key, "resource_") {
			continue
		}
		var resourceKey string
		var isMin bool
		switch {
		case strings.HasSuffix(key, "_min"):
			resourceKey = strings.TrimSuffix(strings.TrimPrefix(key, "resource_"), "_min")
			isMin = true
		case strings.HasSuffix(key, "_max"):
			resourceKey = strings.TrimSuffix(strings.TrimPrefix(key, "resource_"), "_max")
		default:
			continue
		}
		if resourceKey == "" || len(values) == 0 {
			continue
		}
		value := parseOptionalFloat(values[0])
		if value == nil {
			continue
		}
		numberRange := ranges[resourceKey]
		if isMin {
			numberRange.Min = value
		} else {
			numberRange.Max = value
		}
		ranges[resourceKey] = numberRange
	}
	return ranges
}

func firstNonEmpty(values ...string) string {
	for _, value := range values {
		if strings.TrimSpace(value) != "" {
			return value
		}
	}
	return ""
}
