{{ define "import/additional/page" }}
	"git.noahlan.cn/noahlan/ntool-biz/core/page"
{{- end }}

{{ define "pagination" }}
    {{- /*gotype: entgo.io/ent/entc/gen.Graph*/ -}}

    {{ template "header" $ }}
    {{ $pkg := base $.Config.Package }}
    {{ template "import" $ }}

	type PageDetails = page.Pagination

    // OrderDirection defines the directions in which to order a list of items.
    type OrderDirection string

    const (
        // OrderDirectionAsc specifies an ascending order.
        OrderDirectionAsc OrderDirection  = "ASC"
        // OrderDirectionDesc specifies a descending order.
        OrderDirectionDesc OrderDirection = "DESC"
    )

    // Validate the order direction value.
    func (o OrderDirection) Validate() error {
        if o != OrderDirectionAsc && o != OrderDirectionDesc {
            return fmt.Errorf("%s is not a valid OrderDirection", o)
        }
        return nil
    }

    // String implements fmt.Stringer interface.
    func (o OrderDirection) String() string {
        return string(o)
    }

    func (o OrderDirection) reverse() OrderDirection {
        if o == OrderDirectionDesc {
            return OrderDirectionAsc
        }
	    return OrderDirectionDesc
    }

    const errInvalidPagination = "INVALID_PAGINATION"

    {{ range $node := $.Nodes -}}
        {{- if ne $node.Name "CasbinRule" }}
            {{ $pager := print $node.Name "Pager" }}
            {{ $order := print $node.Name "Order"}}
            {{ $query := print $node.Name "Query"}}
            {{ $orderField := print $node.Name "OrderField"}}
            type {{ $pager }} struct {
            Order {{ lower $node.Name }}.OrderOption
            Filter func(*{{ $query }}) (*{{ $query }}, error)
            }

            {{ $opt := print $node.Name "PaginateOption" }}
            // {{ $opt }} enables pagination customization.
            type {{ $opt }} func(*{{ $pager }})


            {{ $newPager := print "new" $node.Name "Pager" -}}
            {{- $defaultOrder := print "Default" $node.Name "Order" }}

            // {{ $defaultOrder }} is the default ordering of {{ $node.Name }}.
            var {{ $defaultOrder }} = Desc({{ lower $node.Name }}.FieldID)

            func {{ $newPager }}(opts []{{ $opt }}) (*{{ $pager }}, error) {
            pager := &{{ $pager }}{}
            for _, opt := range opts {
            opt(pager)
            }
            if pager.Order == nil {
                pager.Order = {{ $defaultOrder }}
            }
            return pager, nil
        }


        func (p *{{ $pager }}) ApplyFilter(query *{{ $query }}) (*{{ $query }}, error) {
            if p.Filter != nil {
                return p.Filter(query)
            }
            return query, nil
        }

           {{ $pageList := print $node.Name "PageList" -}}
        {{ $name := $node.Name }}

        // {{ $pageList }} is {{ $name }} PageList result.
        type {{ $pageList }} struct {
            List []*{{ $name }}      `json:"list"`
            PageDetails *PageDetails  `json:"pageDetails"`
        }


        {{ $r := $node.Receiver -}}
        {{ $queryName := print $node.QueryName -}}

        func ({{ $r }} *{{ $queryName }}) Page(
            ctx context.Context, pageNum uint64, pageSize uint64, opts ...{{ $opt }},
            ) (*{{ $pageList }}, error) {

            pager, err := {{ $newPager }}(opts)
            if err != nil {
                return nil, err
            }

            if {{ $r }}, err = pager.ApplyFilter({{ $r }}); err != nil {
                return nil, err
            }

            ret := &{{ $pageList }}{}

            ret.PageDetails = &PageDetails{
				Current: int64(pageNum),
				Size:    int64(pageSize),
			}

			acClone := {{ $r }}.Clone()
            acClone.modifiers = {{ $r }}.modifiers
            count, err := acClone.Count(ctx)

            if err != nil {
                return nil, err
            }

            ret.PageDetails.Total = int64(count)

            if pager.Order != nil {
           		{{ $r }} = {{ $r }}.Order(pager.Order)
           	} else {
           		{{ $r }} = {{ $r }}.Order({{ $defaultOrder }})
           	}

            {{ $r }} = {{ $r }}.Offset(int((pageNum - 1) * pageSize)).Limit(int(pageSize))
            list, err := {{ $r }}.All(ctx)
            if err != nil {
                return nil, err
            }
            ret.List = list

            return ret, nil
        }
    {{- end}}
    {{- end}}
{{- end}}