package bootable

import (
	"strings"

	"git.simanc.com/software/golib/v4/features/mo"
	"git.simanc.com/software/golib/v4/infra/ii"
)

// handleSinglePoint 处理带 . 的字段查找
// 适用于 object 类型的查找
func (q *Filter) handleSinglePoint(reqName string, value any, info *ii.ItemInfo, matcher *mo.Matcher) {
	fieldName, subFieldName, ok := strings.Cut(reqName, ".")
	if !ok {
		return
	}
	field, ok := info.Field(fieldName)
	if !ok {
		return
	}
	if !field.NoField {

	}
	subField, ok := field.SubField(subFieldName)
	if !ok {
		return
	}
	val, err := subField.Convert(value)
	if err != nil {
		return
	}
	switch field.Type {
	// 子 map 查找
	case mo.TypeObject:
		q.handleField(matcher, field, reqName, val, false)
	case mo.TypeArray:
		if field.Items != ii.FieldItemsObject {
			return
		}
		match := new(mo.Matcher)
		q.handleField(match, subField, subFieldName, val, false)
		q.handleField(matcher, field, fieldName, match, false)
	}
}

func (q *Filter) handleField(matcher *mo.Matcher, field ii.FieldInfo, key string, val any, custom bool) {
	if custom {
		matcher.Add(key, val)
		return
	}
	// 将请求参数值转换为 XML 配置文件中的类型
	val, err := field.Convert(val)
	if err != nil {
		return
	}
	// 详情见 ii utils.go 中 isEnabledType 已启用的类型
	switch field.Type {
	case mo.TypeString:
		// 字符串类型使用正则表达式搜索
		matcher.Regex(key, strings.TrimSpace(val.(string)))
	case mo.TypeDouble:
		matcher.Gte(key, val)
		matcher.Lte(key, val.(float64)+1)
	case mo.TypeInt64:
		matcher.Gte(key, val)
	case mo.TypeArray:
		if field.Items == ii.FieldItemsObject {
			matcher.ElemMatch(key, val.(*mo.Matcher))
		} else {
			matcher.In(key, val.(mo.A))
		}
	default:
		matcher.Eq(key, val)
	}
}

func (q *Filter) handleParams(itemInfo *ii.ItemInfo, items ii.Items, matcher *mo.Matcher, doc mo.D, custom bool) {
	for _, ele := range doc {
		// 检查请求参数中的字段是否包含在 XML 配置文件中
		field, ok := itemInfo.Field(ele.Key)
		if !ok {
			switch strings.Count(ele.Key, ".") {
			case 1:
				q.handleSinglePoint(ele.Key, ele.Value, itemInfo, matcher)
			case 2:
				// lookup filter
				q.handle2Point(matcher, itemInfo, items, ele.Key, ele.Value)
			default:
				// 处理聚合操作符
				if strings.HasPrefix(ele.Key, "$") {
					arr, ok := ele.Value.(mo.A)
					if !ok {
						continue // 聚合操作的 value 必然是一个 mo.A 类型
					}
					var skip bool
					for _, val := range arr {
						evd, o := val.(mo.D) // 其元素也必然是 mo.D 类型
						if !o {
							continue
						}
						// 循环 mo.D 内的 key 是否存在于 XML 内
						for _, ev := range evd {
							// 由于聚合的值是多样的，此处不再判断数据类型, 因此前端必须传入正确的数据类型
							if _, o = itemInfo.Field(ev.Key); !o {
								skip = true
								break
							}
						}
					}
					if !skip {
						q.handleField(matcher, field, ele.Key, ele.Value, custom)
					}
				}
			}
			continue
		}
		if field.Type == mo.TypeDateTime {
			q.handleDateTime(matcher, field, ele.Value)
			continue
		}
		q.handleField(matcher, field, ele.Key, ele.Value, custom)
	}
}
