package confmgr

import (
	"errors"
	"testing"
)

func TestSnapshotCapturesAndCoerces(t *testing.T) {
	set := ConfigSet{
		ID:   "set1",
		Name: "s",
		Parameters: []Parameter{
			{Key: "v", DS: "epics", Signal: "PSU:V", Type: TypeFloat},
			{Key: "n", DS: "epics", Signal: "PSU:N", Type: TypeInt},
			{Key: "en", DS: "epics", Signal: "PSU:EN", Type: TypeBool},
			{Key: "mode", DS: "epics", Signal: "PSU:MODE", Type: TypeEnum, EnumValues: []string{"off", "low", "high"}},
			{Key: "wf", DS: "epics", Signal: "PSU:WF", Type: TypeFloatArray},
			{Key: "lbl", DS: "epics", Signal: "PSU:LBL", Type: TypeString},
		},
	}
	live := map[string]any{
		"PSU:V":    24.5,
		"PSU:N":    3.0,      // float reading → coerced to int64
		"PSU:EN":   int64(1), // numeric → bool true
		"PSU:MODE": int64(2), // enum index → "high"
		"PSU:WF":   []float64{1, 2, 3},
		"PSU:LBL":  "ready",
	}
	res := Snapshot(set, func(_, signal string) (any, error) {
		v, ok := live[signal]
		if !ok {
			return nil, errors.New("not read")
		}
		return v, nil
	})

	if res.Captured != 6 || res.Failed != 0 {
		t.Fatalf("summary: captured=%d failed=%d", res.Captured, res.Failed)
	}
	if res.Values["v"] != 24.5 {
		t.Errorf("v = %v, want 24.5", res.Values["v"])
	}
	if res.Values["n"] != int64(3) {
		t.Errorf("n = %v (%T), want int64(3)", res.Values["n"], res.Values["n"])
	}
	if res.Values["en"] != true {
		t.Errorf("en = %v, want true", res.Values["en"])
	}
	if res.Values["mode"] != "high" {
		t.Errorf("mode = %v, want high", res.Values["mode"])
	}
	if res.Values["lbl"] != "ready" {
		t.Errorf("lbl = %v, want ready", res.Values["lbl"])
	}
	// The captured values must validate against the set.
	inst := ConfigInstance{SetID: set.ID, Values: res.Values}
	if err := inst.ValidateAgainst(set); err != nil {
		t.Errorf("snapshot values fail validation: %v", err)
	}
}

func TestSnapshotReadFailureRecorded(t *testing.T) {
	set := ConfigSet{
		ID:   "set1",
		Name: "s",
		Parameters: []Parameter{
			{Key: "a", DS: "epics", Signal: "A", Type: TypeFloat},
			{Key: "b", DS: "epics", Signal: "B", Type: TypeFloat},
		},
	}
	res := Snapshot(set, func(_, signal string) (any, error) {
		if signal == "B" {
			return nil, errors.New("offline")
		}
		return 1.0, nil
	})
	if res.Captured != 1 || res.Failed != 1 {
		t.Fatalf("summary: captured=%d failed=%d", res.Captured, res.Failed)
	}
	if _, ok := res.Values["b"]; ok {
		t.Errorf("failed parameter must not appear in values")
	}
}
