package utils

import (
	"encoding/base64"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/tidbcloud/tiinf/errs"
)

const (
	DefaultPageSize = 100

	offset = "offset"
)

func GetPageItems(items interface{}, pageToken string, skip int, pageSize int) (totalSize int, pageItems interface{}, nextPageToken string, err error) {
	t := reflect.TypeOf(items)
	if t.Kind() != reflect.Slice {
		return 0, nil, "", errs.NewBadRequest("items is not slice", nil)
	}
	v := reflect.ValueOf(items)

	totalSize = v.Len()

	if pageSize == 0 {
		pageSize = DefaultPageSize
	}
	var startIndex = 0
	if pageToken != "" {
		offset, err := GetOffsetFromPageToken(pageToken)
		if err != nil {
			return 0, nil, "", errs.NewBadRequest("get offset from page_token error", err)
		}
		startIndex = offset
	} else if skip != 0 {
		startIndex = skip
	}

	if startIndex >= v.Len() {
		//invalid pagination parameter, return an empty result set
		return totalSize, reflect.MakeSlice(t, 0, 0).Interface(), "", nil
	}

	endIndex := startIndex + pageSize
	hasNext := true
	if endIndex >= totalSize {
		endIndex = totalSize
		hasNext = false
	}

	reflectSlice := reflect.MakeSlice(t, 0, endIndex-startIndex)
	for i := startIndex; i < endIndex; i++ {
		reflectSlice = reflect.Append(reflectSlice, v.Index(i))
	}
	pageItems = reflectSlice.Interface()

	if hasNext {
		nextPageToken = GenNextPageToken(endIndex)
	}

	return totalSize, pageItems, nextPageToken, nil
}

func GenNextPageToken(index int) string {
	str := fmt.Sprintf("%s:%d", offset, index)
	return base64.StdEncoding.EncodeToString([]byte(str))
}

func GetOffsetFromPageToken(pageToken string) (int, error) {
	if pageToken == "" {
		return 0, nil
	}
	decoded, err := base64.StdEncoding.DecodeString(pageToken)
	if err != nil {
		return 0, err
	}
	parts := strings.Split(string(decoded), ":")
	if len(parts) != 2 || parts[0] != offset {
		return 0, errs.NewBadRequest("bad page_token", nil)
	}
	loffset, err := strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return 0, err
	}
	return int(loffset), nil
}
