package agentnode

import (
	"encoding/json"
	"testing"
	"time"
)

func routeTestNode(id, status string, enabled bool, capabilities map[string]any) Node {
	raw, _ := json.Marshal(capabilities)
	return Node{ID: id, Code: id, Status: status, Enabled: enabled, Capabilities: raw, LastHeartbeatAt: func() *time.Time { now := time.Now(); return &now }()}
}

func TestSelectRouteCandidatesFiltersCapabilitiesAndStatus(t *testing.T) {
	nodes := []Node{
		routeTestNode("online-capable", "online", true, map[string]any{"tool_exec": true, "region": "cn"}),
		routeTestNode("online-disabled-capability", "online", true, map[string]any{"tool_exec": false}),
		routeTestNode("online-missing-capability", "online", true, map[string]any{"region": "cn"}),
		routeTestNode("offline-capable", "offline", true, map[string]any{"tool_exec": true}),
		routeTestNode("disabled-capable", "online", false, map[string]any{"tool_exec": true}),
	}
	selected := selectRouteCandidates(nodes, "request-1", []string{"tool_exec"})
	if len(selected) != 1 || selected[0].ID != "online-capable" {
		t.Fatalf("unexpected candidates: %#v", selected)
	}
}

func TestSelectRouteCandidatesIsDeterministic(t *testing.T) {
	nodes := []Node{
		routeTestNode("node-a", "online", true, nil),
		routeTestNode("node-b", "online", true, nil),
		routeTestNode("node-c", "online", true, nil),
	}
	first := selectRouteCandidates(nodes, "request-42", nil)
	second := selectRouteCandidates([]Node{nodes[2], nodes[0], nodes[1]}, "request-42", nil)
	if len(first) != len(second) || len(first) == 0 {
		t.Fatalf("candidate lengths differ: %d %d", len(first), len(second))
	}
	for index := range first {
		if first[index].ID != second[index].ID {
			t.Fatalf("selection order is not stable: first=%v second=%v", first, second)
		}
	}
	if first[0].ID == first[1].ID {
		t.Fatal("candidate order contains duplicates")
	}
}

func TestNormalizeRoutePreviewInput(t *testing.T) {
	input, err := normalizeRoutePreviewInput(RoutePreviewInput{
		PoolType: " PUBLIC ", PoolCode: "shared", RequestKey: " request-1 ",
		RequiredCapabilities: []string{"tool_exec", " tool_exec ", ""},
	})
	if err != nil || input.PoolType != "public" || input.RequestKey != "request-1" || len(input.RequiredCapabilities) != 1 {
		t.Fatalf("normalized input=%+v err=%v", input, err)
	}
	if _, err := normalizeRoutePreviewInput(RoutePreviewInput{PoolType: "public", PoolCode: "shared"}); err == nil {
		t.Fatal("empty request key must be rejected")
	}
}
