package provision

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

// The bootstrap.json key set is a CROSS-REPO contract: it must match felhom-controller's
// internal/bootstrap.Bootstrap exactly. This test pins the emitted key set; the controller's
// bootstrap_test.go ingests the same shape. A drift here (or there) breaks provisioning.
func TestDoc_ContractKeySet(t *testing.T) {
	d := Doc{
		Schema:   SchemaV2,
		Customer: DocCustomer{ID: "c"},
		Hub:      DocHub{URL: "u", RetrievalPassword: "p"},
		LocalAPI: DocLocalAPI{Endpoint: "ep", Fingerprint: "fp", Token: "tok"},
	}
	b, err := d.render()
	if err != nil {
		t.Fatal(err)
	}
	var m map[string]json.RawMessage
	if err := json.Unmarshal(b, &m); err != nil {
		t.Fatal(err)
	}
	assertKeys(t, "top", m, []string{"schema", "customer", "hub", "local_api"})

	var full struct {
		Customer map[string]json.RawMessage `json:"customer"`
		Hub      map[string]json.RawMessage `json:"hub"`
		LocalAPI map[string]json.RawMessage `json:"local_api"`
	}
	if err := json.Unmarshal(b, &full); err != nil {
		t.Fatal(err)
	}
	// v2: customer carries only id; hub carries url + retrieval_password (NO api_key/host_id).
	assertKeys(t, "customer", full.Customer, []string{"id"})
	assertKeys(t, "hub", full.Hub, []string{"url", "retrieval_password"})
	assertKeys(t, "local_api", full.LocalAPI, []string{"endpoint", "fingerprint", "token"})

	if SchemaV2 != "felhom.bootstrap/v2" {
		t.Fatalf("schema drift: %q", SchemaV2)
	}
}

func assertKeys(t *testing.T, label string, m map[string]json.RawMessage, want []string) {
	t.Helper()
	got := make([]string, 0, len(m))
	for k := range m {
		got = append(got, k)
	}
	sort.Strings(got)
	sort.Strings(want)
	if len(got) != len(want) {
		t.Fatalf("%s: key set %v, want %v", label, got, want)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("%s: key set %v, want %v", label, got, want)
		}
	}
}
