package ucca

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestGetStringSlice(t *testing.T) {
	m := map[string]interface{}{
		"refs": []interface{}{"a", "b", 3, "c"}, // non-strings are skipped
		"str":  "not-a-list",
	}
	got := getStringSlice(m, "refs")
	if len(got) != 3 || got[0] != "a" || got[2] != "c" {
		t.Errorf("refs: %v", got)
	}
	if getStringSlice(m, "missing") != nil {
		t.Error("missing key should be nil")
	}
	if getStringSlice(m, "str") != nil {
		t.Error("non-list should be nil")
	}
}

func TestTopByScore_DeterministicCap(t *testing.T) {
	m := map[string]float64{"x": 0.5, "y": 0.9, "z": 0.5, "w": 0.7}
	got := topByScore(m, 2)
	if len(got) != 2 || got[0] != "y" || got[1] != "w" {
		t.Errorf("want [y w], got %v", got)
	}
	all := topByScore(m, 10)
	if all[2] != "x" || all[3] != "z" { // tie 0.5 broken by key string
		t.Errorf("tie-break not deterministic: %v", all)
	}
}

func TestExpandViaGraph_NoSeedsOrRefs(t *testing.T) {
	c := &LegalRAGClient{} // nil httpClient → must not be called on these paths
	if out := c.expandViaGraph(context.Background(), "x", nil); out != nil {
		t.Error("empty hits should return nil")
	}
	hits := []qdrantSearchHit{{ID: 1, Score: 0.8, Payload: map[string]interface{}{"citation_unit": "Art. 1 CRA"}}}
	if out := c.expandViaGraph(context.Background(), "x", hits); len(out) != 1 {
		t.Errorf("no references → unchanged, got %d", len(out))
	}
}

func TestExpandViaGraph_PullsConnectedNorm(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		_ = json.NewEncoder(w).Encode(map[string]interface{}{
			"result": map[string]interface{}{
				"points": []map[string]interface{}{
					{"id": 99, "payload": map[string]interface{}{
						"citation_unit": "CRA Anhang I", "chunk_text": "Sicherheitsanforderungen",
						"source_class": "binding_law", "authority_weight": 100, "regulation_short": "CRA",
					}},
				},
				"next_page_offset": nil,
			},
		})
	}))
	defer srv.Close()

	c := &LegalRAGClient{qdrantURL: srv.URL, httpClient: srv.Client()}
	hits := []qdrantSearchHit{
		{ID: 1, Score: 0.70, Payload: map[string]interface{}{
			"citation_unit": "Art. 13 CRA", "references_out": []interface{}{"CRA Anhang I"},
		}},
	}
	out := c.expandViaGraph(context.Background(), "bp_compliance_ce", hits)
	if len(out) != 2 {
		t.Fatalf("want 2 hits (seed + connected annex), got %d", len(out))
	}
	var found *qdrantSearchHit
	for i := range out {
		if getString(out[i].Payload, "citation_unit") == "CRA Anhang I" {
			found = &out[i]
		}
	}
	if found == nil {
		t.Fatal("connected norm CRA Anhang I was not pulled into the pool")
	}
	if found.Score < 0.64 || found.Score > 0.66 { // 0.70 seed − 0.05 hop penalty
		t.Errorf("connected score = %v, want ~0.65", found.Score)
	}
}
