// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package response

import (
	"net/url"
	"strconv"
)

// PaginationMeta is a structure included in responses for pagination.
type PaginationMeta struct {
	Limit         int    `json:"limit"`
	CurrentOffset int    `json:"current_offset"`
	NextOffset    *int   `json:"next_offset,omitempty"`
	PrevOffset    *int   `json:"prev_offset,omitempty"`
	NextURL       string `json:"next_url,omitempty"`
	PrevURL       string `json:"prev_url,omitempty"`
}

// NewPaginationMeta populates pagination meta data from result parameters
func NewPaginationMeta(offset, limit int, hasMore bool, currentURL string) PaginationMeta {
	pm := PaginationMeta{
		Limit:         limit,
		CurrentOffset: offset,
	}

	// Calculate next/prev offsets, leave nil if not valid pages
	nextOffset := offset + limit
	if hasMore {
		pm.NextOffset = &nextOffset
	}

	prevOffset := offset - limit
	if prevOffset < 0 {
		prevOffset = 0
	}
	if prevOffset < offset {
		pm.PrevOffset = &prevOffset
	}

	// If URL format provided, populate URLs. Intentionally swallow URL errors for now, API should
	// catch missing URLs if we call with bad URL arg (and we care about them being present).
	if currentURL != "" && pm.NextOffset != nil {
		pm.NextURL, _ = setQueryParam(currentURL, "offset", *pm.NextOffset, 0)
	}
	if currentURL != "" && pm.PrevOffset != nil {
		pm.PrevURL, _ = setQueryParam(currentURL, "offset", *pm.PrevOffset, 0)
	}

	return pm
}

func setQueryParam(baseURL, key string, val, defaultVal int) (string, error) {
	u, err := url.Parse(baseURL)
	if err != nil {
		return "", err
	}
	q := u.Query()
	if val == defaultVal {
		// elide param if it's the default value
		q.Del(key)
	} else {
		q.Set(key, strconv.Itoa(val))
	}
	u.RawQuery = q.Encode()
	return u.String(), nil
}
