package utils

import (
	"strconv"

	"github.com/tidbcloud/pkgv2/bizerr"
	"go.einride.tech/aip/pagination"
)

const (
	defaultMaxPageSize     = 100
	defaultPageSize        = 10
	defaultFirstPageNumber = 1
)

type PageNumberPager struct {
	MaxPageSize      uint32
	DefaultPageSize  uint32
	DefaultFirstPage uint32
	page             uint32
	pageSize         uint32
}

func NewPagerNumberPager() *PageNumberPager {
	return &PageNumberPager{
		MaxPageSize:      defaultMaxPageSize,
		DefaultPageSize:  defaultPageSize,
		DefaultFirstPage: defaultFirstPageNumber,
	}
}

func (p *PageNumberPager) Normalize(r pagination.Request) bizerr.BizError {
	pageSize := r.GetPageSize()
	switch {
	case pageSize < 0:
		return bizerr.New(bizerr.ErrCodeParams, "page size is negative")
	case pageSize == 0:
		p.pageSize = p.DefaultPageSize
	case pageSize > int32(p.MaxPageSize):
		p.pageSize = p.MaxPageSize
	default:
		p.pageSize = uint32(pageSize)
	}

	if pageToken := r.GetPageToken(); pageToken == "" {
		p.page = p.DefaultFirstPage
	} else {
		token, err := strconv.ParseUint(pageToken, 10, 32)
		if err != nil {
			return bizerr.New(bizerr.ErrCodeParams, "invalid page token")
		}
		p.page = uint32(token)
	}
	return nil
}

func (p *PageNumberPager) Page() uint32 {
	return p.page
}

func (p *PageNumberPager) PageSize() uint32 {
	return p.pageSize
}

func (p *PageNumberPager) Offset() uint32 {
	return (p.page - 1) * p.pageSize
}

func (p *PageNumberPager) NextPageToken(total uint32) string {
	if p.Offset()+p.PageSize() >= total {
		return ""
	}
	return strconv.FormatUint(uint64(p.page+1), 10)
}
