package connector_callout

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strings"
)

type testAllowlist struct{}

func (testAllowlist) EnsureAllowed(rawURL string) error {
	return ensureTestExternalURL(rawURL)
}

func (testAllowlist) Redact(rawURL string) string {
	u, err := url.Parse(rawURL)
	if err != nil {
		return rawURL
	}
	u.User = nil
	u.RawQuery = ""
	u.Fragment = ""
	return u.String()
}

func (a testAllowlist) RedactError(err error) error {
	if err == nil {
		return nil
	}
	var urlErr *url.Error
	if errors.As(err, &urlErr) && urlErr.URL != "" {
		clone := *urlErr
		clone.URL = a.Redact(urlErr.URL)
		return &clone
	}
	return err
}

func testAllowlistForEngine() URLAllowlist {
	return testAllowlist{}
}

type blockingHTTPClient struct{}

func (blockingHTTPClient) Do(req *http.Request) (*http.Response, error) {
	if err := ensureTestExternalURL(req.URL.String()); err != nil {
		return nil, err
	}
	return http.DefaultClient.Do(req)
}

func ensureTestExternalURL(rawURL string) error {
	u, err := url.Parse(rawURL)
	if err != nil {
		return err
	}
	host := u.Hostname()
	if host == "" {
		return fmt.Errorf("internal addresses are not allowed")
	}
	if strings.EqualFold(host, "localhost") {
		return fmt.Errorf("internal addresses are not allowed")
	}
	ip := net.ParseIP(host)
	if ip != nil && (ip.IsLoopback() || ip.IsPrivate() || ip.IsUnspecified() || ip.IsLinkLocalUnicast()) {
		return fmt.Errorf("internal addresses are not allowed")
	}
	return nil
}
