package confmgr

import (
	"reflect"
	"testing"
)

// TestCoerceSnapshot covers the alternate and error branches of coerceSnapshot
// that the happy-path Snapshot tests do not reach.
func TestCoerceSnapshot(t *testing.T) {
	enum := Parameter{Type: TypeEnum, EnumValues: []string{"off", "low", "high"}}
	cases := []struct {
		name    string
		p       Parameter
		raw     any
		want    any
		wantErr bool
	}{
		{"float err", Parameter{Type: TypeFloat}, struct{}{}, nil, true},
		{"int round", Parameter{Type: TypeInt}, 2.6, int64(3), false},
		{"int err", Parameter{Type: TypeInt}, struct{}{}, nil, true},
		{"bool from string", Parameter{Type: TypeBool}, "true", true, false},
		{"bool bad string", Parameter{Type: TypeBool}, "maybe", nil, true},
		{"bool from numeric", Parameter{Type: TypeBool}, 0.0, false, false},
		{"bool unconvertible", Parameter{Type: TypeBool}, struct{}{}, nil, true},
		{"string passthrough", Parameter{Type: TypeString}, "x", "x", false},
		{"string from numeric", Parameter{Type: TypeString}, 42.0, "42", false},
		{"enum string in range", enum, "low", "low", false},
		{"enum string out of range", enum, "nope", nil, true},
		{"enum index", enum, int64(2), "high", false},
		{"enum index out of range", enum, 9.0, nil, true},
		{"enum non-numeric", enum, struct{}{}, nil, true},
		{"array native", Parameter{Type: TypeFloatArray}, []float64{1, 2}, []float64{1, 2}, false},
		{"array err", Parameter{Type: TypeFloatArray}, 1.0, nil, true},
		{"default passthrough", Parameter{Type: ParamType("weird")}, "asis", "asis", false},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			got, err := tc.p.coerceSnapshot(tc.raw)
			if tc.wantErr {
				if err == nil {
					t.Errorf("coerceSnapshot(%v): want error", tc.raw)
				}
				return
			}
			if err != nil {
				t.Fatalf("coerceSnapshot(%v): %v", tc.raw, err)
			}
			if !reflect.DeepEqual(got, tc.want) {
				t.Errorf("coerceSnapshot(%v) = %v (%T), want %v (%T)", tc.raw, got, got, tc.want, tc.want)
			}
		})
	}
}

// TestSnapshotCoerceFailureRecorded ensures a coercion failure (vs read failure)
// is counted in res.Failed and kept out of Values.
func TestSnapshotCoerceFailureRecorded(t *testing.T) {
	set := ConfigSet{
		ID:   "s",
		Name: "s",
		Parameters: []Parameter{
			{Key: "n", DS: "d", Signal: "N", Type: TypeInt},
		},
	}
	res := Snapshot(set, func(_, _ string) (any, error) {
		return "not-a-number", nil // reads fine, fails coercion
	})
	if res.Captured != 0 || res.Failed != 1 {
		t.Fatalf("summary: captured=%d failed=%d", res.Captured, res.Failed)
	}
	if _, ok := res.Values["n"]; ok {
		t.Error("coercion-failed parameter must not appear in values")
	}
}
