package api

import (
	"net"
	"net/url"
	"strings"
)

// tailscaleCGNAT is the 100.64.0.0/10 carrier-grade NAT range Tailscale hands
// out to nodes; MagicDNS A records resolve into it. A developer hitting the API
// over a Tailscale IP from another device shows up with an origin in this range.
var tailscaleCGNAT = mustCIDR("100.64.0.0/10")

func mustCIDR(s string) *net.IPNet {
	_, n, err := net.ParseCIDR(s)
	if err != nil {
		panic(err)
	}
	return n
}

// devOriginAllowed reports whether a browser Origin should be accepted for CORS
// in non-production mode. It permits the origins a developer realistically
// serves the dashboards from — loopback, RFC1918 LAN addresses, link-local, the
// Tailscale CGNAT range (100.64.0.0/10), and *.ts.net MagicDNS names — on any
// port, so the API "just works" when reached from another device on the tailnet
// or LAN without enumerating every host:port.
//
// It is only wired in non-release builds (see Run). Production keeps the strict
// explicit allowlist and never consults this function.
func devOriginAllowed(origin string) bool {
	u, err := url.Parse(origin)
	if err != nil || u.Host == "" {
		return false
	}
	switch u.Scheme {
	case "http", "https":
	default:
		return false
	}

	host := u.Hostname()
	if host == "localhost" || strings.HasSuffix(host, ".localhost") {
		return true
	}
	if strings.HasSuffix(host, ".ts.net") {
		return true
	}

	ip := net.ParseIP(host)
	if ip == nil {
		return false
	}
	switch {
	case ip.IsLoopback():
		return true
	case ip.IsPrivate(): // RFC1918 (10/8, 172.16/12, 192.168/16) + IPv6 ULA
		return true
	case ip.IsLinkLocalUnicast(): // 169.254/16, fe80::/10
		return true
	case tailscaleCGNAT.Contains(ip):
		return true
	default:
		return false
	}
}
