package provider

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

func ValidateBaseURL(ctx context.Context, raw string, allowPrivate bool) (string, error) {
	parsed, err := url.Parse(strings.TrimSpace(raw))
	if err != nil {
		return "", err
	}
	if (parsed.Scheme != "http" && parsed.Scheme != "https") || parsed.Hostname() == "" {
		return "", errors.New("base_url must be an absolute http(s) URL")
	}
	if parsed.User != nil || parsed.RawQuery != "" || parsed.Fragment != "" {
		return "", errors.New("base_url must not contain user info, query, or fragment")
	}
	if !allowPrivate {
		addresses, err := net.DefaultResolver.LookupIPAddr(ctx, parsed.Hostname())
		if err != nil {
			return "", fmt.Errorf("resolve base_url host: %w", err)
		}
		if len(addresses) == 0 {
			return "", errors.New("base_url host did not resolve")
		}
		for _, address := range addresses {
			if !isPublicAddress(address.IP) {
				return "", fmt.Errorf("base_url resolves to blocked address %s", address.IP)
			}
		}
	}
	parsed.Path = strings.TrimRight(parsed.Path, "/")
	return parsed.String(), nil
}

func isPublicAddress(ip net.IP) bool {
	return ip != nil && !ip.IsPrivate() && !ip.IsLoopback() && !ip.IsLinkLocalUnicast() &&
		!ip.IsLinkLocalMulticast() && !ip.IsMulticast() && !ip.IsUnspecified()
}
