func NewHTTPAPIClientDefaultWithTimeout(duration time.Duration) (httpclient.Client, error) {
	hcConfig := &httpclient.Config{
		Paginator: httpclient.NoPaginator(),
		Retryable: httpclient.NewBackoffRetry(10*time.Millisecond, 100*time.Millisecond, duration, 2.0),
	}
	return NewHTTPAPIClient(hcConfig)
}
NewHTTPAPIClientDefaultWithTimeout will return a new HTTP client for talking with the Pinpoint API
it will only allow a trusted TLS connection with a valid TLS certificate signed
by a trusted Certificate Authority and for a DNS name that is owned by Pinpoint
the client will retry requests by default with a expotential backoff. The max duration to wait
is supplied for how long to take at most to try and send data
package api
import (
	"context"
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"path"
	"regexp"
	"strings"
	"time"
	"github.com/pinpt/go-common/v10/httpdefaults"
	"github.com/pinpt/go-common/v10/json"
	"github.com/pinpt/httpclient"
)
const baseURL = "pinpoint.com/"
const devbaseURL = "ppoint.io"
const AuthorizationHeader = "Authorization"
const userAgentFormat = "Pinpoint Agent/%s"
var (
	domainRegex = regexp.MustCompile("\\.(pinpt|ppoint|pinpoint)\\.(net|com|io|co)$")
	caWeTrust = map[string]bool{
		"fbe3018031f9586bcbf41727e417b7d1c45c2f47f93be372a17b96b50757d5a2": true,  
		"7f4296fc5b6a4e3b35d3c369623e364ab1af381d8fa7121533c9d6c633ea2461": true,  
		"36abc32656acfc645c61b71613c4bf21c787f5cabbee48348d58597803d7abc9": true,  
		"f7ecded5c66047d28ed6466b543c40e0743abe81d109254dcf845d4c2c7853c5": true,  
		"b58539ecaa13921ccdb80d38d34875fde6471c5a159d9beef2fa6f99983bd611": true,  
		"64bb5bd80311fa3f53bd99404cab8762ad6e048447d0a97f219fceca1661f37c": true,  
		"1bda5afff83781380bf708198f9f7d2db1e067f14bb9ea7bae70aac0b0305e7b": true,  
		"7c53b5df79135d9af6195ef6bb73ab98c2c89950b892b192dffd784db925a41c": true,  
		"17708dff2b7faec9cb1b5215ebb2421d97b0543c936fac9d6e02b92f20e5c707": true,  
		"60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18": true,  
	}
	caWeTrustDev = map[string]bool{
		"e1ae9c3de848ece1ba72e0d991ae4d0d9ec547c6bad1dddab9d6beb0a7e0e0d8": true,  
	}
)
func isTrusted(cert *x509.Certificate, addr string) bool {
	der, _ := x509.MarshalPKIXPublicKey(cert.PublicKey)
	hash := sha256.Sum256(der)
	fingerprint := fmt.Sprintf("%x", hash)
	if caWeTrust[fingerprint] {
		return true
	}
	if caWeTrustDev[fingerprint] && strings.Contains(addr, devbaseURL) {
		return true
	}
	return false
}
func isDNSNameTrusted(names ...string) bool {
	for _, name := range names {
		if domainRegex.MatchString(name) {
			return true
		}
	}
	return false
}
const (
	AgentService = "agent.api"
	AppService = "app"
	AuthService = "auth.api"
	EventService = "event.api"
	RegistryService = "registry.api"
	GraphService = "graph.api"
	WebhookService = "webhook.api"
)
func BackendURL(subdomain string, channel string) string {
	switch channel {
	case "internal":
		switch subdomain {
		case AgentService:
			return os.Getenv("PP_AGENT_SERVICE")
		case AppService:
			return os.Getenv("PP_APP_SERVICE")
		case AuthService:
			return os.Getenv("PP_AUTH_SERVICE")
		case EventService:
			return os.Getenv("PP_EVENT_SERVICE")
		case RegistryService:
			return os.Getenv("PP_REGISTRY_SERVICE")
		case GraphService:
			return os.Getenv("PP_GRAPHQL_SERVICE")
		case WebhookService:
			return os.Getenv("PP_WEBHOOK_SERVICE")
		}
	case "stable", "":
		return fmt.Sprintf("https://%s.%s", subdomain, baseURL)
	case "dev":
		switch subdomain {
		case AgentService:
			return fmt.Sprintf("https://%s.%s:3004/", subdomain, devbaseURL)
		case AppService:
			return fmt.Sprintf("https://%s.%s:3001/", subdomain, devbaseURL)
		case AuthService:
			return fmt.Sprintf("https://%s.%s:3000/", subdomain, devbaseURL)
		case EventService:
			return fmt.Sprintf("https://%s.%s:8443/", subdomain, devbaseURL)
		case RegistryService:
			return fmt.Sprintf("https://%s.%s:8444/", subdomain, devbaseURL)
		case GraphService:
			return fmt.Sprintf("https://%s.%s:3010/", subdomain, devbaseURL)
		case WebhookService:
			return fmt.Sprintf("https://%s.%s:8454/", subdomain, devbaseURL)
		}
	}
	return fmt.Sprintf("https://%s.%s.%s", subdomain, channel, baseURL)
}
func incasesensitiveEnv(name string) string {
	val := strings.ToLower(name)
	for _, env := range os.Environ() {
		kv := strings.Split(env, "=")
		if strings.ToLower(kv[0]) == val {
			return kv[1]
		}
	}
	return ""
}
func isUsingProxy() bool {
	return incasesensitiveEnv("https_proxy") != "" ||
		incasesensitiveEnv("http_proxy") != "" ||
		incasesensitiveEnv("all_proxy") != ""
}
func NewHTTPAPIClient(config *httpclient.Config) (httpclient.Client, error) {
	t := httpdefaults.DefaultTransport()
	if !isUsingProxy() {
		t.DialTLS = func(network, addr string) (net.Conn, error) {
			config := &tls.Config{
				InsecureSkipVerify: false,
			}
			conn, err := tls.Dial(network, addr, config)
			if err != nil {
				return nil, err
			}
			state := conn.ConnectionState()
			var certtrusted, catrusted bool
			for _, cert := range state.PeerCertificates {
				if !cert.IsCA {
					if isDNSNameTrusted(cert.DNSNames...) {
						certtrusted = true
					}
				}
				if cert.IsCA && isTrusted(cert, addr) {
					catrusted = true
					break
				}
			}
			if certtrusted && catrusted {
				return conn, nil
			}
			conn.Close()
			return nil, fmt.Errorf("invalid TLS certificate. expected a valid Certificate signed by a trusted Pinpoint Certificate Authority and well known domain")
		}
	} else {
		t.TLSNextProto = make(map[string]func(authority string, c *tls.Conn) http.RoundTripper)
	}
	client := &http.Client{
		Transport: t,
	}
	if config == nil {
		config = httpclient.NewConfig()
	}
	hc := httpclient.NewHTTPClient(context.Background(), config, client)
	return hc, nil
}
func NewHTTPAPIClientDefault() (httpclient.Client, error) {
	hcConfig := &httpclient.Config{
		Paginator: httpclient.NoPaginator(),
		Retryable: httpclient.NewBackoffRetry(10*time.Millisecond, 100*time.Millisecond, 10*time.Second, 2.0),
	}
	return NewHTTPAPIClient(hcConfig)
}