package divert

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestBuildFilter_HappyPath(t *testing.T) {
	got := BuildFilter(FilterParams{
		TargetPIDs: []uint32{12345, 67890},
		OwnPID:     999,
		UpstreamIP: "95.165.72.59",
	})
	// Required clauses
	assert.Contains(t, got, "outbound")
	assert.Contains(t, got, "(tcp or udp)")
	assert.Contains(t, got, "ip")
	assert.Contains(t, got, "processId == 12345")
	assert.Contains(t, got, "processId == 67890")
	assert.Contains(t, got, "processId != 999")
	assert.Contains(t, got, "ip.DstAddr != 95.165.72.59")
	// Loopback / multicast / link-local exclusions
	assert.Contains(t, got, "127.0.0.0")
	assert.Contains(t, got, "224.0.0.0")
	assert.Contains(t, got, "169.254.0.0")
}

func TestBuildFilter_SinglePID(t *testing.T) {
	got := BuildFilter(FilterParams{
		TargetPIDs: []uint32{42},
		OwnPID:     1,
		UpstreamIP: "1.2.3.4",
	})
	assert.Contains(t, got, "processId == 42")
}

func TestBuildFilter_NoTargetPIDs(t *testing.T) {
	// No Discord running. We still produce a syntactically valid filter
	// that matches nothing (we can't pass an empty filter to WinDivert).
	got := BuildFilter(FilterParams{
		TargetPIDs: nil,
		OwnPID:     999,
		UpstreamIP: "1.2.3.4",
	})
	// "false" alone is a valid filter that captures nothing — perfect
	// for "Discord not running" interim.
	assert.Equal(t, "false", got)
}

func TestBuildFilter_OwnPIDNotInTargets(t *testing.T) {
	// Defensive: even if OwnPID accidentally appears in TargetPIDs, the
	// processId != ownPid clause still excludes it.
	got := BuildFilter(FilterParams{
		TargetPIDs: []uint32{999, 1234},
		OwnPID:     999,
		UpstreamIP: "1.2.3.4",
	})
	assert.Contains(t, got, "processId != 999")
	// The exclusion takes precedence syntactically because of the AND.
	assert.True(t, strings.Contains(got, "and processId != 999"))
}

func TestBuildFilter_UpstreamIPv4Format(t *testing.T) {
	got := BuildFilter(FilterParams{
		TargetPIDs: []uint32{1},
		OwnPID:     2,
		UpstreamIP: "not-an-ip",
	})
	// We just substitute a placeholder and document it.
	assert.Contains(t, got, "ip.DstAddr != 0.0.0.0")
}
