package paginate

import (
	"net/http"
	"strconv"
)

const (
	DefaultLimit = 20
	MaxLimit     = 100
)

// PageInfo holds pagination metadata returned alongside the data.
type PageInfo struct {
	Total   int  `json:"total"`
	Limit   int  `json:"limit"`
	Offset  int  `json:"offset"`
	HasNext bool `json:"has_next"`
	HasPrev bool `json:"has_prev"`
}

// Page is the generic paginated response envelope.
type Page[T any] struct {
	Data       []T      `json:"data"`
	Pagination PageInfo `json:"pagination"`
}

// NewPage constructs a Page from a slice already fetched from the DB
// (which owns the limit/offset), the total record count, and the Params
// that were passed to the query.
func NewPage[T any](data []T, total int, p Params) Page[T] {
	if data == nil {
		data = []T{}
	}
	return Page[T]{
		Data: data,
		Pagination: PageInfo{
			Total:   total,
			Limit:   int(p.Limit),
			Offset:  int(p.Offset),
			HasNext: int(p.Offset)+int(p.Limit) < total,
			HasPrev: p.Offset > 0,
		},
	}
}

// Params holds parsed limit/offset values
type Params struct {
	Limit  int32
	Offset int32
}

// ParseParams reads "limit" and "offset" from the request query string and
// returns safe, clamped values. Invalid or missing values fall back to defaults.
//
//	GET /bots?limit=10&offset=30
func ParseParams(r *http.Request) Params {
	limit := parseIntParam(r, "limit", DefaultLimit)
	offset := parseIntParam(r, "offset", 0)

	if limit <= 0 {
		limit = DefaultLimit
	}
	if limit > MaxLimit {
		limit = MaxLimit
	}
	if offset < 0 {
		offset = 0
	}

	return Params{
		Limit:  int32(limit),
		Offset: int32(offset),
	}
}

func parseIntParam(r *http.Request, key string, fallback int) int {
	raw := r.URL.Query().Get(key)
	if raw == "" {
		return fallback
	}
	v, err := strconv.Atoi(raw)
	if err != nil {
		return fallback
	}
	return v
}
