package api

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/api/errs"
	"github.com/davecgh/go-spew/spew"
	"github.com/eugeniucarvalho/validator"
	"github.com/kataras/iris/v12/context"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"golang.org/x/crypto/bcrypt"
)

var (
	AcceptJson = regexp.MustCompile("^application/json")

	Environment = map[string]interface{}{}
	ToReference = references{}
	Format      = fmt.Sprintf
	Dump        = spew.Dump
)

type references struct {
}

func (this *references) True() *bool {
	value := true
	return &value
}

func (this *references) False() *bool {
	value := false
	return &value
}

func (this *references) String(value string) *string {
	return &value
}

func (this *references) Bool(value bool) *bool {
	return &value
}

func (this *references) Int(value int) *int {
	return &value
}

func (this *references) Int32(value int32) *int32 {
	return &value
}

func (this *references) Int64(value int64) *int64 {
	return &value
}

func (this *references) Float32(value float32) *float32 {
	return &value
}

func (this *references) Float64(value float32) *float32 {
	return &value
}

type ModeInterface interface {
	Mode() string
}

type PatchHistoryRegister struct {
	Id        primitive.ObjectID `bson:"_id" json:"-"`
	CreatedAt int64              `bson:"createdAt" json:"-"`
	CreatedBy string             `bson:"createdBy" json:"-"`
	Parent    string             `bson:"parent" json:"-"`
	ApiTags   []string           `bson:"apiTags" json:"-"`
}

type EntityModel struct {
	// Id        primitive.ObjectID `bson:"_id" json:"-"`
	Mode               string  `bson:"-" json:"-"`
	ApplicationVersion *string `bson:"appVersion,omitempty" json:"-"`
	Deleted            *bool   `bson:"deleted,omitempty" json:"-"`
	DeletedIn          *int64  `bson:"deletedIn,omitempty" json:"-"`
}

// type DotNotation struct {
// 	Rules map[string]interface{} `bson:",inline" json:"-"`
// }

// func (model *DotNotation) DotNotation() map[string]interface{} {

// 	if model.Rules == nil {
// 		model.Rules = map[string]interface{}{}
// 	}
// 	return model.Rules
// }


func PasswordBcryptHash(password string)(hash string, err *errs.Error) { 
	var (
		bytes  []byte
		errgen error
	)

	if bytes, errgen = bcrypt.GenerateFromPassword(
		[]byte(password),
		14,
	); errgen != nil {
		err = errs.Internal().Details(&errs.Detail{
			Reason:  "passwordHashFailed",
			Message: "Falha ao processar a senha",
		})
		return
	}

	hash = string(bytes)
	return
}

func UserIDString(ctx context.Context) (id string, err *errs.Error) {

	if user, ok := ctx.Values().Get("$user.ref").(map[string]interface{}); ok {
		id = user["id"].(primitive.ObjectID).Hex()
		return
	}
	err = errs.Internal().Details(&errs.Detail{
		Message: "Invalid user instance",
	})
	return
}

func (model *EntityModel) SetMode(mode string) {
	model.Mode = mode
	switch mode {
	case "create":
		model.ApplicationVersion = &BuildVersion
		deleted := false
		model.Deleted = &deleted

	case "update":
		if model.Deleted == nil {
			deleted := false
			model.Deleted = &deleted
		}
	case "patch":
		// if model.Deleted == nil {
		// 	deleted := false
		// 	model.Deleted = &deleted
		// }
		// case "delete":
		// case "undelete":
	}

}

func GetIDString(input interface{}) (string, *errs.Error) {

	if value, converted := input.(string); converted {
		return value, nil
	}
	if value, converted := input.(*primitive.ObjectID); converted {
		return value.Hex(), nil
	}
	if value, converted := input.(primitive.ObjectID); converted {
		return value.Hex(), nil
	}

	return "", errs.Internal().Details(&errs.Detail{
		Reason: fmt.Sprintf("Can't convert ID into string. Invalid type '%T", input),
	})
}

func NowUnix() int64 {
	return time.Now().Unix()
}

func GetUser(ctx context.Context) interface{} {
	return ctx.Values().Get("$user.ref")
}

func (model *EntityModel) SetDeleted(deleted bool) {
	var deletedIn = int64(0)
	model.Deleted = &deleted
	if *model.Deleted {
		deletedIn = time.Now().Unix()
	}
	model.DeletedIn = &deletedIn
}

type CorsOptions struct {
	ExposeHeaders []string
	AllowHeaders  []string
	AllowMethods  []string
	AllowOrigin   []string
}

type GetManyResponse struct {
	ResultSizeEstimate int         `json:"resultSizeEstimate"` // Estimativa do numero total de itens.
	NextPageToken      string      `json:"nextPageToken"`      // Referência para a proxima pagina de resultados.
	Itens              interface{} `json:"itens"`              // Lista contento os elementos da resposta.
}

var (
	// ParamsFlag         map[string]*ParamFlag
	CorsDefaultOptions = CorsOptions{
		AllowOrigin: []string{"*"},
		// AllowOrigin:   []string{"http://localhost:4200"},
		AllowMethods:  []string{"OPTIONS", "GET", "POST", "PUT", "DELETE", "PATCH"},
		AllowHeaders:  []string{"Accept", "Authorization", "Content-Type", "Origin", "Host", "x-api-build"},
		ExposeHeaders: []string{"X-total-count"},
	}

	BuildVersion = "0"
	ApiVersion   = "0"
	// Armazena os mimes dos arquivos consultados
	// MimeCache    = xmap.NewMS2S()

	replaceEmpty = regexp.MustCompile(`\s+`)
	// pageTokenRegex = regexp.MustCompile(`(?P<ids>\w+):(?P<idc>\w+):(?P<page>\d{1,6})`)
	pageTokenRegex = regexp.MustCompile(`(?P<idc>[\w-]+):(?P<count>\d+)`)
	replaceIndex   = regexp.MustCompile(`\.\d+\.`)
)

func init() {
	// fmt.Println("Register validation functions")
	// err := Validator.RegisterValidation("req", func(f validator.FieldLevel) bool {
	// 	fmt.Println("Running req validation")
	// 	spew.Dump(f)
	// 	return true
	// })

	validator.RegisterValidator("requiredOnCreate", func(i interface{}, o interface{}, v *validator.ValidatorOption) error {

		if schema, ok := o.(ModeInterface); ok {
			fmt.Println("requiredOnCreate ->", schema.Mode())
			switch schema.Mode() {
			case "create":
				if i == nil {
					return fmt.Errorf("")
				}
			case "update":
			}
		}

		return nil
	})
	// Validator.RegisterValidation("req",
	// 	func(fl validator.FieldLevel) bool {
	// 		// func(v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
	// 		// func(v *validator.Validate, param string) bool {
	// 		// return passwordRegex.MatchString(field.String())

	// 	})

	// if err != nil {
	// 	panic(err)
	// }
}
func Panic() {
	if err := recover(); err != nil {
		LogError(0, err.(error).Error())
	}
}
func Validate(i interface{}) *errs.Error {

	// if err := Validator.Struct(i); err != nil {

	// fmt.Println("VALIDATE", result, err)
	// spew.Dump(i)
	if errors, valid := validator.Struct(i); !valid {

		err := errs.InvalidArgument()

		// er := Error(ERR_INVALID_PARAM, "Invalid params")

		for _, e := range errors {
			err.Details(&errs.Detail{
				Dominio: "global",
				Reason:  "invalidParameter",
				Message: e.Message,
				// Message: fmt.Sprintf("%+v", e.Message),
				// LocationType:,
				// Location     :,
			})
		}

		// if _, ok := err.(*validator.InvalidValidationError); ok {
		// 	fmt.Println("INvalid")
		// 	er.LastDescription().Message = err.Error()

		// } else {

		// 	for _, err := range err.(validator.ValidationErrors) {

		// 		switch err.Tag() {
		// 		case "required":

		// 		}

		// 		er.Add(&ErrDescription{
		// 			Dominio: "global",
		// 			Reason:  "invalidParameter",
		// 			Message: fmt.Sprintf("%+v", err),
		// 			// LocationType:,
		// 			// Location     :,
		// 		})

		// 		// fmt.Println("1", err.Namespace())
		// 		// fmt.Println("2", err.Field())
		// 		// fmt.Println("3", err.StructNamespace()) // can differ when a custom TagNameFunc is registered or
		// 		// fmt.Println("4", err.StructField())     // by passing alt name to ReportError like below
		// 		// fmt.Println("5", err.Tag())
		// 		// fmt.Println("6", err.ActualTag())
		// 		// fmt.Println("7", err.Kind())
		// 		// fmt.Println("8", err.Type())
		// 		// fmt.Println("9", err.Value())
		// 		// fmt.Println("10", err.Param())
		// 		// fmt.Println("-------------")
		// 	}

		// }
		return err
		// from here you can create your own error messages in whatever language you wish
	}
	return nil
}

// ApiResponse é a estrutura padrão de respostas
// Apenas os campos preenchidos serão retornados
type ApiResponse struct {
	Entity             interface{} `json:"entity,omitempty"`
	List               interface{} `json:"list,omitempty"`
	NextPageToken      string      `json:"nextPageToken,omitempty"`
	ResultSizeEstimate int         `json:"resultSizeEstimate,omitempty"`
}

// func ErroCtxHandler(ctx context.Context, err *errs.Error) {

// 	if accept := ctx.GetHeader("Accept"); AcceptJson.Match([]byte(accept)) {
// 		ctx.JSON(err)
// 	} else {
// 		ctx.ViewData("", err)
// 	}

// }

func finalizeRequest(ctx context.Context, resp interface{}, err *errs.Error) {
	var (
		status = 200
		accept = ctx.Request().Header.Get("accept")
		types  = strings.Split(accept, ",")
	)

	defer func() {
		ctx.StopExecution()

		if debug := ctx.Values().Get("#debug"); debug != nil {
			go func() {
				debug.(*DebugTaks).Finalize()
			}()
		}

		if err != nil {

			ctx.Application().Logger().Error(err.Error())
			if description := err.LastDescription(); description != nil {
				err.Stack.Print()
				// ctx.Application().Logger().Error(fmt.Printf("%s\n%s\n", description.Reason, description.Message))
			}

			// ctx.Application().Logger().Error()
			spew.Dump(err)
		}

		fmt.Println("defer of finalizeRequest")
		if r := recover(); r != nil {
			fmt.Println("Recovered in f", r)
		}
		// fmt.Println(string(ctx.Values().Serialize()))
	}()

	if err != nil {
		status = err.HttpStatus

		// fmt.Println(status, err.Message, "------------------------------------------\n")
		// spew.Dump(err)
		// debbug
		// err.Stack.Print()
		resp = err
		abortTransaction(ctx)
		// fmt.Println("------------------------------------------\n", status)
		// spew.Dump(err)
		// fmt.Println("------------------------------------------\n", status)
	}

	ctx.Values().Set("res", resp)
	ctx.Header("x-api-build", BuildVersion)
	// fmt.Println("error")
	// spew.Dump(resp)
	// spew.Dump(types)
	// spew.Dump(ctx.Request().Header)
	ctx.StatusCode(status)

	for _, mime := range types {
		switch mime {
		case "application/json":
			ctx.JSON(resp)
			return
		}
	}
	// default response case
	ctx.WriteString("invalid accept header value: " + accept)
}

// Call encapsula e trata os erros para cada requisição.
func CallAction(id string, fn func(context.Context) (interface{}, *errs.Error)) func(context.Context) {
	return func(ctx context.Context) {
		var (
			err      *errs.Error
			resp     interface{}
			finalize = true
			values   = ctx.Values()
		)

		if debug, activeDebug := values.Get("#debug").(*DebugTaks); activeDebug {
			debug.Stage(id)
		}

		defer func() {

			if !ctx.IsStopped() {

				if _err := recover(); _err != nil {

					err = errs.Internal().Details(&errs.Detail{
						Message:      "",
						Location:     fmt.Sprintf("call.action.%s", id),
						LocationType: "application.pipe.resource.stage",
						Reason:       _err.(error).Error(),
					})
				}

				if finalize {
					finalizeRequest(ctx, resp, err)
				}
			}
		}()

		fmt.Println("apply -> ", id)

		if resp, err = fn(ctx); err != nil {
			return
		}

		if !ctx.IsStopped() {

			if resp != nil {
				err = commitTransaction(ctx)
			} else {
				ctx.Next()
				finalize = false
			}
		}
		return
	}
}

func abortTransaction(ctx context.Context) (err *errs.Error) {
	return transactionHandler(ctx, "abort")
}

func commitTransaction(ctx context.Context) (err *errs.Error) {
	return transactionHandler(ctx, "commit")
}

func transactionHandler(ctx context.Context, action string) (err *errs.Error) {
	var (
		localErr  error
		operation func() error
	)
	contextSession := GetSessionContext(ctx)

	if contextSession == nil {
		return
	}

	switch action {
	case "abort":
		operation = func() error { return contextSession.AbortTransaction(contextSession) }
	case "commit":
		operation = func() error { return contextSession.CommitTransaction(contextSession) }
	}

	defer func() {
		if localErr != nil {
			err = errs.Internal().Details(&errs.Detail{
				Message: localErr.Error(),
			})
		}
	}()
	try := 4

	for {
		if localErr = operation(); localErr == nil {
			fmt.Println(action, "executed ")
			return
		}
		if try == 0 {
			return
		}
		try--

		fmt.Println(action, "transaction error loop ")
		// time.Sleep(4 * time.Second)
		// retry operation when command contains TransientTransactionError
		// if cmdErr, ok := localErr.(mongo.CommandError); ok && cmdErr.HasErrorLabel("TransientTransactionError") {
		if cmdErr, ok := localErr.(mongo.CommandError); ok {
			fmt.Println(action, cmdErr)
			if cmdErr.HasErrorLabel("TransientTransactionError") {
				continue
			}
		}
	}
}

func ReadJson(ctx context.Context, entity interface{}) (err *errs.Error) {
	if err := ctx.ReadJSON(entity); err != nil {
		err = errs.DataCaps().Details(&errs.Detail{
			Message: err.Error(),
		})
	}
	return
}

func MgoSortBson(fields []string) *bson.M {
	order := bson.M{}
	for _, field := range fields {
		n := 1
		if field != "" {
			fmt.Printf("sort '%c'\n", field[0])
			switch field[0] {
			case '+':
				field = field[1:]
			case '-':
				n = -1
				field = field[1:]
			default:
				panic(fmt.Sprintf("Invalid sort field %s.", field))
			}
		}
		if field == "" {
			panic("Sort: empty field name")
		}
		field = string(replaceIndex.ReplaceAll([]byte(field), []byte(".")))
		order[field] = n
	}
	return &order
}

func MgoSort(ctx context.Context, field string) []string {
	result := []string{}
	if fields := Q(ctx, field, ""); fields != "" {
		sort := string(replaceEmpty.ReplaceAll([]byte(fields), []byte("")))

		result = strings.Split(sort, ",")
	}
	// return nil
	return result
}

func MgoFieldsCtx(ctx context.Context, field string) *bson.M {
	return MgoFields(Q(ctx, field, ""))
}

func MgoFields(fields string) (projection *bson.M) {

	// fmt.Printf("MgoFields '%s'\n", fields)
	if fields != "" {
		projection = &bson.M{}
		for _, v := range strings.Split(fields, ",") {
			(*projection)[v] = 1
		}
		// spew.Dump(projection)
	}
	return
}

func MgoQuery(ctx context.Context, field string) (*bson.M, *errs.Error) {
	return MgoQueryString(ctx, Q(ctx, field, ""))
}

func MgoQueryString(ctx context.Context, query string) (*bson.M, *errs.Error) {
	var (
		selector = make(bson.M)
		// id       = "_id"
		err error
	)

	// Unmarshal json query if any
	if query != "" {

		if err = bson.UnmarshalExtJSON([]byte(query), true, &selector); err != nil {
			// return nil, Error(ERR_GENERAL, err.Error())
			return nil, errs.Internal().Details(&errs.Detail{
				Message: err.Error(),
			})
		}

		if query, err = url.QueryUnescape(query); err != nil {
			return nil, errs.Internal().Details(&errs.Detail{
				Message: err.Error(),
			})
			// return nil, Error(ERR_GENERAL, err.Error())
		}
		if err = json.Unmarshal([]byte(query), &selector); err != nil {
			// return nil, Error(ERR_GENERAL, err.Error())
			return nil, errs.Internal().Details(&errs.Detail{
				Message: err.Error(),
			})
		}
		// if selector, err = mejson.Unmarshal(selector); err != nil {
		// 	return nil, Error(ERR_GENERAL, err.Error())
		// }
	}

	// Transform string HexId to ObjectIdHex
	// if selid, _ := selector[id].(string); selid != "" {
	// 	if bson.IsObjectIdHex(selid) {
	// 		selector[id] = bson.ObjectIdHex(selid)
	// 	}
	// 	//  else {
	// 	// 	selector[id] = selid
	// 	// }
	// }
	return &selector, nil
}

func DefaultCorsHandler() func(ctx context.Context) {
	return Cors(CorsDefaultOptions)
}

func Cors(opt CorsOptions) func(ctx context.Context) {
	return func(ctx context.Context) {

		ctx.Header("Access-Control-Allow-Credentials", "true")

		if len(opt.AllowOrigin) > 0 {
			// ctx.Header("Access-Control-Allow-Origin", strings.Join(opt.AllowOrigin, ","))
			// ctx.Header("Access-Control-Allow-Origin", "*")
			// ctx.Header("Origin", "*")
			ctx.Header("Access-Control-Allow-Origin", ctx.GetHeader("Origin"))
		}
		if len(opt.AllowMethods) > 0 {
			ctx.Header("Access-Control-Allow-Methods", strings.Join(opt.AllowMethods, ","))
		}
		if len(opt.AllowHeaders) > 0 {
			ctx.Header("Access-Control-Allow-Headers", strings.Join(opt.AllowHeaders, ","))
		}
		if len(opt.ExposeHeaders) > 0 {
			ctx.Header("Access-Control-Expose-Headers", strings.Join(opt.ExposeHeaders, ","))
		}
		ctx.Next()
	}
}

// Retorna um valor de um parametro no path da url.
func P(ctx context.Context, name string, def string) string {
	val := ctx.Params().Get(name)
	if val == "" {
		val = def
	}
	return val
}

//Retorna um valor de um parametro da query. Ex: ?x=1
func Q(ctx context.Context, name string, def string) string {
	val := ctx.URLParam(name)
	if val == "" {
		val = def
	}
	return val
}

//Retorna um valor de um parametro da query
func QInt(ctx context.Context, name string, def int) int {
	val, e := strconv.Atoi(Q(ctx, name, ""))
	if e != nil {
		val = def
	}
	return val
}

// Retorna um valor de um parametro do post.
func F(ctx context.Context, name string, def interface{}) interface{} {
	var val interface{}
	val = ctx.FormValue(name)
	if val == "" {
		val = def
	}
	return val
}

func LogError(code int, m string) {
	log("31", fmt.Sprintf("[ERROR| %d] %s", code, m))
}

func LogInfo(code int, m string) {
	log("34", fmt.Sprintf("[INFO| %d] %s", code, m))
}

func LogWarning(code int, m string) {
	log("35", fmt.Sprintf("[WARNING| %d] %s", code, m))
}

func log(color string, m string) {
	fmt.Printf("\x1b[%s;1m%s\x1b[0m\n", color, m)
}

func ObjectIDFromHex(objectId string) (id primitive.ObjectID, err *errs.Error) {
	var errd error

	if id, errd = primitive.ObjectIDFromHex(objectId); errd != nil {
		err = errs.InvalidArgument().Details(&errs.Detail{
			Message: errd.Error(),
			Reason:  "InvalidArgument",
		})
	}
	return
}

// func ParseRequestTest(ctx context.Context) {
// 	var (
// 		err    error
// 		filter = &Filter{
// 			MaxResults: QInt(ctx, "maxResults", 10),
// 		}
// 		oid primitive.ObjectID
// 	)
// 	// parse parameter of path
// 	id := P(ctx, "userId", "")

// 	if oid, err = primitive.ObjectIDFromHex(id); err != nil {
// 		filter.UserId = oid
// 	}

// 	id = P(ctx, "id", "")
// 	if oid, err = primitive.ObjectIDFromHex(id); err != nil {
// 		filter.Id = oid
// 	}

// 	// filter.PageToken.Parse(Q(ctx, "nextPageToken", ""))

// 	if filter.Query, err = MgoQuery(ctx, "q"); err != nil {
// 		goto Error
// 	}

// 	filter.Format = Q(ctx, "format", "full")
// 	filter.Sort = MgoSortBson(MgoSort(ctx, "sort"))
// 	filter.Fields = MgoFieldsCtx(ctx, "fields")

// Error:
// 	if err != nil {
// 		ErroCtxHandler(
// 			ctx,
// 			// Error(ERR_INVALID_PARAM, err.Error()),

// 			errs.Internal().Details(&errs.Detail{
// 				Message: err.Error(),
// 			}),
// 		)
// 		return
// 	}

// 	ctx.Values().Set("$filter", filter)

// 	ctx.Next()
// }

// func MapError(erro *errs.Error) *errs.Error {

// 	if strings.Contains(erro.Message, "E11000") {

// 		return errs.AlreadyExists().Details(&errs.Detail{
// 			Message: "DUPLICATED_ITEM",
// 		})

// 	} else if strings.Contains(erro.Message, "no documents in result") {
// 		return errs.Internal().Details(&errs.Detail{
// 			Message: "NOT_FOUND",
// 		})
// 	}

// 	return erro
// }

// type PageToken struct {
// 	// StartID   string
// 	// CurrentID string
// 	Cursor    string
// 	NewCursor string
// 	Page      int
// 	Count     int
// }

// // Encode cria um novo token formatado
// func (p *PageToken) Encode() string {
// 	out := ""
// 	if p.NewCursor != "" {
// 		out = base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%d", p.NewCursor, p.Count)))
// 	}
// 	return out
// 	// return string([]byte(fmt.Sprintf("%s:%d", p.NewCursor, p.Count)))
// }

// // HasToken determina se a requisição apresenta um token de paginacao
// func (p *PageToken) HasToken() bool {
// 	return p.Cursor != ""
// }

// // func (p *PageToken) GetBsonID() bson.ObjectId {
// // 	if !bson.IsObjectIdHex(p.ID) {
// // 		return nil
// // 	}
// // 	return bson.ObjectIdHex(p.ID)
// // }

// func (p *PageToken) Parse(s string) error {
// 	var (
// 		decoded []byte
// 		err     error
// 	)

// 	if decoded, err = base64.StdEncoding.DecodeString(s); err != nil {
// 		return err
// 	}

// 	match := pageTokenRegex.FindStringSubmatch(string(decoded))

// 	if len(match) != 3 {
// 		return fmt.Errorf("Invalid Page Token")
// 	}

// 	p.Cursor = match[1]
// 	// p.Page, err = strconv.Atoi(match[2])
// 	p.Count, err = strconv.Atoi(match[2])

// 	return err
// }

// Layout aplica o path do layout

// func Layout(ctx context.Context) {
// 	ctx.ViewLayout(ViewScript(ctx, "layout/layout.html"))
// 	ctx.Next()
// }

// // ViewScript devolve o path do arquivo de script a ser renderizaco
// func ViewScript(ctx context.Context, filename string) string {
// 	var (
// 		base string
// 		ok   bool
// 	)
// 	domain := strings.Split(ctx.Request().Host, ":")[0]

// 	if base, ok = TemplateDomainMap[domain]; !ok {
// 		base = "default"
// 	}
// 	return base + "/" + filename
// }

// defer func() {
// 	var (
// 		erro *errs.Error
// 		// ok   bool
// 		err error
// 	)

// 	if err = recover(); err != nil {

// 		if erro, ok = err.(*errs.Error); !ok {
// 			erro = Error(ERR_GENERAL, err.Error())
// 		}

// 		ErroCtxHandler(ctx, erro)
// 	}
// 	// ctx.Header("Accept", "application/json")
// 	// spew.Dump(err)
// }()

// func CallAction(f func(context.Context, *ApiResponse) *errs.Error) func(ctx context.Context) {
// 	return func(ctx context.Context) {
// 		var (
// 			err      *errs.Error
// 			response = &ApiResponse{}
// 		)
// 		if err = f(ctx, response); err != nil {
// 			ErroCtxHandler(ctx, err)
// 			return
// 		}

// 		ctx.JSON(response)
// 	}
// }

// Verifica se existe alguma pagina para ser carragada.

// func UpdateCursorResponse(models *Mongo, f *Filter, resp interface{}) bool {

// 	count := f.PageToken.Count
// 	// Se não foi encontrado nenhum registro

// 	if count > 0 {

// 		resp.ResultSizeEstimate = count
// 		resp.NextPageToken = f.PageToken.Encode()

// 		return true
// 	}
// 	return false

// }
