package netsettings

import (
	"context"
	"errors"
	"testing"
)

// A nil service reaches middleware in test routers and anywhere the settings
// aren't wired. It must read as "trust nothing" rather than panic — the
// alternative is a nil dereference inside RequireUser, on every request.
func TestHops_NilServiceTrustsNothing(t *testing.T) {
	var s *Service
	if got := s.Hops(); got != 0 {
		t.Errorf("(*Service)(nil).Hops() = %d, want 0", got)
	}
}

func TestNew_NilPoolYieldsDefault(t *testing.T) {
	s, err := New(context.Background(), nil, nil)
	if err != nil {
		t.Fatalf("New with nil pool: %v", err)
	}
	if s == nil {
		t.Fatal("New returned nil service")
	}
	if got := s.Hops(); got != DefaultTrustedProxyHops {
		t.Errorf("Hops() = %d, want %d", got, DefaultTrustedProxyHops)
	}
}

// Range is rejected before the query so the API answers 400 rather than
// surfacing a CHECK violation as a 500.
func TestSetHops_RejectsOutOfRange(t *testing.T) {
	s, _ := New(context.Background(), nil, nil)
	for _, hops := range []int{-1, MaxTrustedProxyHops + 1, 999} {
		if err := s.SetHops(context.Background(), hops); !errors.Is(err, ErrHopsOutOfRange) {
			t.Errorf("SetHops(%d) error = %v, want ErrHopsOutOfRange", hops, err)
		}
	}
}

// In-range values with no pool must still fail, and must not mutate the
// cache — a write that didn't persist reporting success would leave the
// running process disagreeing with the database.
func TestSetHops_NoPoolFailsWithoutMutatingCache(t *testing.T) {
	s, _ := New(context.Background(), nil, nil)
	before := s.Hops()
	if err := s.SetHops(context.Background(), 2); err == nil {
		t.Error("SetHops with nil pool returned nil error")
	}
	if after := s.Hops(); after != before {
		t.Errorf("cache changed from %d to %d despite a failed write", before, after)
	}
}
