package bootable

import (
	"io"

	"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"
)

func ResolveFilter(reader io.Reader) (Filter, error) {
	b, err := io.ReadAll(reader)
	if err != nil {
		return Filter{}, err
	}
	return ResolveFilterFrom(b)
}

func ResolveFilterFrom(b []byte) (Filter, error) {
	var filter Filter
	return filter, mo.UnmarshalExtJSON(b, true, &filter)
}

// Handler 数据处理
type Handler func(info *ii.ItemInfo, row mo.M)

func FindHandle(user ii.User, itemName ii.Name, filter Filter, handler Handler) (*Response, error) {
	itemInfo, ok := svc.HasItem(itemName)
	if !ok {
		return nil, svc.ErrItemNotfound
	}
	filter.user = user
	bootFilter, err := filter.Build(itemInfo, svc.GetItems())
	if err != nil {
		return nil, err
	}

	service := svc.With(user)

	resp := new(Response)
	resp.Rows = make([]mo.M, 0)

	if err = service.Aggregate(itemName, bootFilter, &resp.Rows); err != nil {
		return nil, err
	}

	handleRows(itemInfo, resp, handler)

	if len(filter.Filter) == 0 {
		// 当界面传入 Custom 请求参数时, 根据条件合计出文档数量, 用于翻页
		if _, value, o := mo.HasOptWith(bootFilter, mo.ArgMatch); o {
			resp.Total, err = service.CountDocuments(itemName, &mo.Matcher{Filter: value.(mo.D)})
		} else {
			resp.Total, err = service.EstimatedDocumentCount(itemName)
		}
	} else {
		// 当 filter control 含有查询条件时, 根据条件合计出文档数量, 用于翻页
		if _, value, o := mo.HasOptWith(bootFilter, mo.ArgMatch); o {
			resp.Total, err = service.CountDocuments(itemName, &mo.Matcher{Filter: value.(mo.D)})
		} else {
			resp.Total = int64(len(resp.Rows))
		}
	}
	return resp, err
}

func Find(user ii.User, itemName ii.Name, filter Filter) (*Response, error) {
	return FindHandle(user, itemName, filter, nil)
}
