func ReasonHeader(r string) http.Header {
	h := http.Header{}
	if r != "" {
		h.Set("X-Audit-Log-Reason", r)
	}
	return h
}
ReasonHeader returns an HTTP header with the Audit Log reason set to r.
package rest
import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httputil"
	"time"
	"github.com/skwair/harmony/internal/endpoint"
	"github.com/skwair/harmony/internal/rate"
	"github.com/skwair/harmony/log"
	"github.com/skwair/harmony/version"
)
var baseURL = "https://discord.com/api/v" + version.REST()
type rateLimitResp struct {
	Message    string  `json:"message"`
	RetryAfter float64 `json:"retry_after"`
	Global     bool    `json:"global"`
}
type Client struct {
	httpClient *http.Client
	limiter    *rate.Limiter
	token      string
	name       string
	logger     log.Logger
}
func NewClient(httpClient *http.Client, token, name string, logger log.Logger) *Client {
	return &Client{
		httpClient: httpClient,
		limiter:    rate.NewLimiter(),
		token:      token,
		name:       name,
		logger:     logger,
	}
}
func (c *Client) Do(ctx context.Context, e *endpoint.Endpoint, p *Payload) (*http.Response, error) {
	return c.DoWithHeader(ctx, e, p, nil)
}
func (c *Client) DoWithHeader(ctx context.Context, e *endpoint.Endpoint, p *Payload, h http.Header) (*http.Response, error) {
	var (
		err error
		req *http.Request
	)
	if p.hasBody() {
		req, err = http.NewRequestWithContext(ctx, e.Method, baseURL+e.Path, bytes.NewReader(p.body))
	} else {
		req, err = http.NewRequestWithContext(ctx, e.Method, baseURL+e.Path, nil)
	}
	if err != nil {
		return nil, err
	}
	for k, vs := range h {
		for _, v := range vs {
			req.Header.Add(k, v)
		}
	}
	if p.hasBody() {
		req.Header.Set("Content-Type", p.contentType)
	}
	req.Header.Set("Authorization", c.token)
	ua := fmt.Sprintf("%s (github.com/skwair/harmony, %s)", c.name, version.Module())
	req.Header.Set("User-Agent", ua)
	c.limiter.Wait(e.Key)
	if c.logger.Level() == log.LevelDebug {
		b, _ := httputil.DumpRequestOut(req, true)
		c.logger.Debug("--> ", string(b))
	}
	before := time.Now()
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	if c.logger.Level() == log.LevelDebug {
		b, _ := httputil.DumpResponse(resp, true)
		c.logger.Debug("<-- ", time.Since(before), "\n", string(b))
	}
	c.limiter.Update(e.Key, resp.Header)
	date, err := http.ParseTime(resp.Header.Get("Date"))
	if err != nil {
		return nil, fmt.Errorf("could not parse date header: %w", err)
	}
	now := time.Now()
	if now.Sub(before) < time.Second &&
		(now.Before(date.Add(-1500*time.Millisecond)) ||
			now.After(date.Add(1500*time.Millisecond))) {
		c.logger.Warnf("time desynchronization detected (server UTC time: %s, local UTC time: %s), rate limit will be inaccurate and you may encounter 429s, consider using NTP to synchronize time", date.UTC(), now.Round(time.Second).UTC())
	}
	if resp.StatusCode == http.StatusTooManyRequests {
		var r rateLimitResp
		if err = json.NewDecoder(resp.Body).Decode(&r); err != nil {
			return nil, err
		}
		time.Sleep(time.Millisecond * time.Duration(r.RetryAfter*100))
		return c.DoWithHeader(ctx, e, p, h)
	}
	return resp, nil
}
func Do(ctx context.Context, e *endpoint.Endpoint, p *Payload) (*http.Response, error) {
	return DoWithHeader(ctx, e, p, nil)
}
func DoWithHeader(ctx context.Context, e *endpoint.Endpoint, p *Payload, h http.Header) (*http.Response, error) {
	var (
		err error
		req *http.Request
	)
	if p.hasBody() {
		req, err = http.NewRequest(e.Method, baseURL+e.Path, bytes.NewReader(p.body))
	} else {
		req, err = http.NewRequest(e.Method, baseURL+e.Path, nil)
	}
	if err != nil {
		return nil, err
	}
	req = req.WithContext(ctx)
	for k, vs := range h {
		for _, v := range vs {
			req.Header.Add(k, v)
		}
	}
	if p.hasBody() {
		h.Set("Content-Type", p.contentType)
	}
	ua := fmt.Sprintf("%s (github.com/skwair/harmony, %s)", "Harmony", version.Module())
	req.Header.Set("User-Agent", ua)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode == http.StatusTooManyRequests {
		var r rateLimitResp
		if err = json.NewDecoder(resp.Body).Decode(&r); err != nil {
			return nil, err
		}
		time.Sleep(time.Millisecond * time.Duration(r.RetryAfter*100))
		return DoWithHeader(ctx, e, p, h)
	}
	return resp, nil
}