package resolver_test

import (
	"context"
	"ekdns/resolver"
	"io"
	"testing"
	"time"
)

// ---------------------------------------------------------------------------
// CheckSplitHorizon tests (T015)
// ---------------------------------------------------------------------------

func TestCheckSplitHorizon_NoConflict_SameIPs(t *testing.T) {
	qname := mustNewName("www.example.com.")

	localAddr := startFakeDNSMulti(t, func(query []byte) []byte {
		return buildAResponse(queryID(query), qname, [][4]byte{{93, 184, 216, 34}})
	})

	authIPs := []string{"93.184.216.34"}
	result := resolver.CheckSplitHorizon(
		context.Background(),
		io.Discard,
		[]string{localAddr},
		"www.example.com",
		authIPs,
		"ns1.example.com",
		2*time.Second,
	)

	if result.HasConflict {
		t.Errorf("expected no conflict when IPs match, got conflict: local=%v auth=%v",
			result.LocalIPs, result.AuthoritativeIPs)
	}
}

func TestCheckSplitHorizon_Conflict_DifferentIPs(t *testing.T) {
	qname := mustNewName("www.example.com.")

	// Local resolver returns internal IP.
	localAddr := startFakeDNSMulti(t, func(query []byte) []byte {
		return buildAResponse(queryID(query), qname, [][4]byte{{10, 0, 5, 100}})
	})

	authIPs := []string{"203.0.113.50"} // authoritative returned a different IP
	result := resolver.CheckSplitHorizon(
		context.Background(),
		io.Discard,
		[]string{localAddr},
		"www.example.com",
		authIPs,
		"ns1.example.com",
		2*time.Second,
	)

	if !result.HasConflict {
		t.Error("expected conflict when IPs differ")
	}
	if len(result.LocalIPs) == 0 {
		t.Error("expected LocalIPs to be populated")
	}
	if result.LocalSource == "" {
		t.Error("expected LocalSource to be populated")
	}
}

func TestCheckSplitHorizon_NoConflict_LocalNXDOMAIN(t *testing.T) {
	qname := mustNewName("www.example.com.")

	localAddr := startFakeDNSMulti(t, func(query []byte) []byte {
		return buildNXDOMAINResponse(queryID(query), qname)
	})

	authIPs := []string{"93.184.216.34"}
	result := resolver.CheckSplitHorizon(
		context.Background(),
		io.Discard,
		[]string{localAddr},
		"www.example.com",
		authIPs,
		"ns1.example.com",
		2*time.Second,
	)

	if result.HasConflict {
		t.Error("expected no conflict when local returns NXDOMAIN")
	}
	if result.LocalIPs != nil {
		t.Errorf("expected nil LocalIPs for NXDOMAIN, got %v", result.LocalIPs)
	}
}

func TestCheckSplitHorizon_NoConflict_LocalTimeout(t *testing.T) {
	silentAddr := startSilentDNS(t)

	authIPs := []string{"93.184.216.34"}
	result := resolver.CheckSplitHorizon(
		context.Background(),
		io.Discard,
		[]string{silentAddr},
		"www.example.com",
		authIPs,
		"ns1.example.com",
		100*time.Millisecond,
	)

	if result.HasConflict {
		t.Error("expected no conflict when local resolver times out")
	}
	if result.LocalIPs != nil {
		t.Errorf("expected nil LocalIPs for timeout, got %v", result.LocalIPs)
	}
}

func TestCheckSplitHorizon_NoConflict_OrderIndependent(t *testing.T) {
	qname := mustNewName("www.example.com.")

	// Local resolver returns IPs in different order than authoritative.
	localAddr := startFakeDNSMulti(t, func(query []byte) []byte {
		return buildAResponse(queryID(query), qname, [][4]byte{
			{5, 6, 7, 8},
			{1, 2, 3, 4},
		})
	})

	// Authoritative had them in reverse order.
	authIPs := []string{"1.2.3.4", "5.6.7.8"}
	result := resolver.CheckSplitHorizon(
		context.Background(),
		io.Discard,
		[]string{localAddr},
		"www.example.com",
		authIPs,
		"ns1.example.com",
		2*time.Second,
	)

	if result.HasConflict {
		t.Errorf("expected no conflict for same IPs in different order: local=%v auth=%v",
			result.LocalIPs, result.AuthoritativeIPs)
	}
}

func TestCheckSplitHorizon_NoLocalResolvers(t *testing.T) {
	authIPs := []string{"93.184.216.34"}
	result := resolver.CheckSplitHorizon(
		context.Background(),
		io.Discard,
		nil, // no local resolvers
		"www.example.com",
		authIPs,
		"ns1.example.com",
		2*time.Second,
	)

	if result.HasConflict {
		t.Error("expected no conflict when no local resolvers provided")
	}
	if result.LocalIPs != nil {
		t.Error("expected nil LocalIPs when no resolvers provided")
	}
}
