package bootable

import (
	"strings"

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

// handle2Point
// 支持:
// 1. 反向查找子 Lookup 关联数据
// 2. Array 类型且 Items=object 时的查找
func (q *Filter) handle2Point(matcher *mo.Matcher, info *ii.ItemInfo, items ii.Items, name string, value any) {
	k := strings.Split(name, ".")
	if len(k) != 3 {
		return
	}

	fieldName := k[0]
	pointName := k[1]
	subFieldName := k[2]

	field, ok := info.Field(fieldName)
	if !ok {
		return
	}
	subField, ok := field.SubField(subFieldName)
	if !ok {
		return
	}
	// 如果类型为 array 且 items=object 时认定为数组 object 查找
	if field.Type == mo.TypeArray && field.Items == ii.FieldItemsObject {
		v, err := subField.Convert(value)
		if err != nil {
			return
		}
		q.handleField(matcher, subField, name, v, false)
	}
	// 如果不存在 Lookup 选项或 List 为 true 则不允许查找
	look, ok := field.HasLookup(pointName)
	if !ok || (look.SUM == "" && look.List || look.SUM != "" && look.List) {
		return
	}

	// 获取 Lookup 关联的 ItemName
	lookItem, ok := items.Has(info.ForkDb(look.From))
	if !ok {
		return
	}
	// 关联的 itemInfo 中是否包含该字段
	lookField, ok := lookItem.Field(subFieldName)
	if !ok {
		return
	}
	val, err := lookField.Convert(value)
	if err != nil {
		return
	}
	// 仅处理 SUM 为空的搜索
	if look.SUM == "" {
		if oid, o := q.getForeign(lookItem, lookField, val, look.ForeignField); o {
			matcher.In(field.Name, oid)
		}
	}
}

func (q *Filter) getForeign(itemInfo *ii.ItemInfo, field ii.FieldInfo, val any, foreignField string) (mo.A, bool) {
	lookMatch := &mo.Matcher{}
	q.handleField(lookMatch, field, field.Name, val, false)

	project := &mo.Projects{}
	project.AddEnable(field.Name)
	if foreignField != mo.OID {
		project.AddEnable(foreignField)
	}
	var data []mo.M
	if err := svc.With(q.user).Aggregate(itemInfo.Name, mo.NewPipeline(project, lookMatch), &data); err != nil {
		return nil, false
	}
	oid := make(mo.A, len(data))
	for i, row := range data {
		oid[i] = row[foreignField]
	}
	return oid, true
}
