package webui

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestRequestIPTrustedProxy(t *testing.T) {
	a := &App{trustedProxies: parseTrustedProxies("10.0.0.0/8", nil)}

	cases := []struct {
		name       string
		remoteAddr string
		headers    map[string]string
		want       string
	}{
		{
			name:       "untrusted RemoteAddr ignores X-Forwarded-For entirely",
			remoteAddr: "203.0.113.5:12345",
			headers:    map[string]string{"X-Forwarded-For": "1.2.3.4"},
			want:       "203.0.113.5", // a client with nothing in front of it can't spoof its own IP
		},
		{
			name:       "trusted proxy: X-Forwarded-For honored",
			remoteAddr: "10.0.0.1:12345",
			headers:    map[string]string{"X-Forwarded-For": "198.51.100.9"},
			want:       "198.51.100.9",
		},
		{
			name:       "trusted proxy: walks from the right, skipping other trusted hops",
			remoteAddr: "10.0.0.1:12345",
			headers:    map[string]string{"X-Forwarded-For": "198.51.100.9, 10.0.0.2"},
			want:       "198.51.100.9", // 10.0.0.2 is itself trusted (in 10.0.0.0/8) — skip it, land on the real client
		},
		{
			name:       "trusted proxy: CF-Connecting-IP preferred over X-Forwarded-For",
			remoteAddr: "10.0.0.1:12345",
			headers:    map[string]string{"CF-Connecting-IP": "198.51.100.9", "X-Forwarded-For": "attacker-spoofed-should-be-ignored"},
			want:       "198.51.100.9",
		},
		{
			name:       "no trusted_proxies configured: header ignored even from that same peer",
			remoteAddr: "203.0.113.5:12345",
			headers:    map[string]string{"X-Real-IP": "1.2.3.4"},
			want:       "203.0.113.5",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			req := httptest.NewRequest(http.MethodGet, "/", nil)
			req.RemoteAddr = tc.remoteAddr
			for k, v := range tc.headers {
				req.Header.Set(k, v)
			}
			if got := a.requestIP(req); got != tc.want {
				t.Errorf("requestIP() = %q, want %q", got, tc.want)
			}
		})
	}
}

func TestParseTrustedProxiesCloudflarePreset(t *testing.T) {
	prefixes := parseTrustedProxies("cloudflare", nil)
	if len(prefixes) != len(cloudflareRanges) {
		t.Fatalf("expected %d cloudflare ranges parsed, got %d", len(cloudflareRanges), len(prefixes))
	}
}

func TestParseTrustedProxiesBareIP(t *testing.T) {
	prefixes := parseTrustedProxies("192.0.2.10", nil)
	if len(prefixes) != 1 {
		t.Fatalf("expected 1 prefix, got %d", len(prefixes))
	}
	if prefixes[0].Bits() != 32 {
		t.Fatalf("expected a bare IPv4 to become a /32, got /%d", prefixes[0].Bits())
	}
}
