package tool

import (
	"context"
	"errors"
	"github.com/syyongx/php2go"
	"math"
	"reflect"
	"strconv"
)

//这里放一些数据库用到的公用方法

// 第n页，默认每页10行
func Page(page int64) (S, E int64) {
	offset := (page - 1) * 10
	length := int64(10)

	return offset, length
}

// page 数据
func PageNum(page, num int32) (S, E int32) {
	return (page - 1) * num, num
}

func PageS(page int64) (S, E string) {
	offset := (page - 1) * 10
	length := int64(10)

	return strconv.FormatInt(offset, 10), strconv.FormatInt(length, 10)
}

// 类似商品随机
func PageS4(page int64) (S, E string) {
	offset := (page - 1) * 4
	length := int64(4)

	return strconv.FormatInt(offset, 10), strconv.FormatInt(length, 10)
}

func PageSNum(page, num int64) (S, E string) {
	offset := (page - 1) * num
	return strconv.FormatInt(offset, 10), strconv.FormatInt(num, 10)
}

// 第n页，默认每页10行
func Page30(page int64) (S, E int64) {
	start := (page - 1) * 30
	end := int64(30)
	return start, end
}

func GetPage(page, pagesize string) string {
	index := ""
	Pages, _ := strconv.Atoi(page)
	Pagesizes, _ := strconv.Atoi(pagesize)
	if Pages > 1 {
		index = strconv.Itoa((Pages - 1) * Pagesizes)
	} else {
		index = "0"
	}

	return index
}

type Paginate struct {
	Page     int `json:"page"`
	PageSize int `json:"page_size"`
	Total    int `json:"total"`
	LastPage int `json:"last_page"`
	Data     any
}

func NewPaginate(queryBuild any, page, pageSize int, ctxS ...context.Context) (*Paginate, error) {
	ctx := context.Background()
	if len(ctxS) > 0 {
		ctx = ctxS[0]
	}
	data := make([]any, 0)
	total := 0
	obj := reflect.ValueOf(queryBuild)
	offset := (page - 1) * pageSize

	var structMethods []string
	t := obj.Type()
	for i := 0; i < t.NumMethod(); i++ {
		structMethods = append(structMethods, t.Method(i).Name)
	}

	for _, v := range []string{"Limit", "Offset", "All", "Count"} {
		if !php2go.InArray(v, structMethods) {
			return nil, errors.New("方法不存在:" + v)
		}
	}
	valsCnt := obj.MethodByName("Count").Call([]reflect.Value{reflect.ValueOf(ctx)})
	for _, v := range valsCnt {
		t, ok := v.Interface().(int)
		if ok {
			total = t
		}
	}
	obj.MethodByName("Limit").Call([]reflect.Value{reflect.ValueOf(pageSize)})
	obj.MethodByName("Offset").Call([]reflect.Value{reflect.ValueOf(offset)})
	vals := obj.MethodByName("All").Call([]reflect.Value{reflect.ValueOf(ctx)})
	for _, v := range vals {
		if v.Interface() == nil {
			continue
		}
		data = append(data, v.Interface())

	}
	lastPage := math.Ceil(float64(total) / float64(pageSize))
	return &Paginate{
		Page:     page,
		PageSize: pageSize,
		Total:    total,
		LastPage: int(lastPage),
		Data:     data,
	}, nil
}
