package approvalir

import (
	"strings"
	"testing"
)

func TestFieldUpdateValueKindIsClosed(t *testing.T) {
	valid := []FieldUpdateValueKind{
		FieldUpdateValueKindSourceText,
		FieldUpdateValueKindString,
		FieldUpdateValueKindBoolean,
		FieldUpdateValueKindInteger,
		FieldUpdateValueKindDecimal,
		FieldUpdateValueKindDate,
		FieldUpdateValueKindDateTime,
		FieldUpdateValueKindReference,
	}
	for _, kind := range valid {
		if !kind.Valid() {
			t.Fatalf("defined kind %q reported invalid", kind)
		}
	}
	if FieldUpdateValueKind("raw").Valid() {
		t.Fatal("undefined kind reported valid")
	}
}

func TestFieldUpdateValuePreservesEveryArm(t *testing.T) {
	sourceText := "false"
	emptyString := ""
	falseValue := false
	zero := int64(0)
	date := "2026-07-13"
	datetime := "2026-07-13T07:22:09.123Z"
	reference := "001xx0000000001AAA"
	values := []FieldUpdateValue{
		{Kind: FieldUpdateValueKindSourceText, SourceText: &sourceText},
		{Kind: FieldUpdateValueKindString, String: &emptyString},
		{Kind: FieldUpdateValueKindBoolean, Boolean: &falseValue},
		{Kind: FieldUpdateValueKindInteger, Integer: &zero},
		{Kind: FieldUpdateValueKindDecimal, Decimal: &Decimal{Coefficient: "0", Scale: 2}},
		{Kind: FieldUpdateValueKindDate, Date: &date},
		{Kind: FieldUpdateValueKindDateTime, DateTime: &datetime},
		{Kind: FieldUpdateValueKindReference, Reference: &reference},
		{Kind: FieldUpdateValueKindString, Null: true},
	}
	for index, value := range values {
		if err := value.Validate(); err != nil {
			t.Fatalf("value %d Validate() error = %v", index, err)
		}
	}
	if *values[0].SourceText != "false" || *values[1].String != "" || *values[2].Boolean || *values[3].Integer != 0 {
		t.Fatalf("zero-like values were not preserved: %#v", values[:4])
	}
}

func TestFieldUpdateValueValidateRejectsAmbiguousOrMalformedValues(t *testing.T) {
	text := "value"
	badDate := "07/13/2026"
	badDateTime := "2026-07-13 07:22:09"
	emptyReference := ""
	tests := []struct {
		name    string
		value   FieldUpdateValue
		wantErr string
	}{
		{name: "unknown kind", value: FieldUpdateValue{Kind: "dialect", String: &text}, wantErr: "invalid kind"},
		{name: "missing arm", value: FieldUpdateValue{Kind: FieldUpdateValueKindString}, wantErr: "exactly one non-null arm"},
		{name: "multiple arms", value: FieldUpdateValue{Kind: FieldUpdateValueKindString, String: &text, SourceText: &text}, wantErr: "exactly one non-null arm"},
		{name: "mismatched arm", value: FieldUpdateValue{Kind: FieldUpdateValueKindString, SourceText: &text}, wantErr: "does not match"},
		{name: "null with arm", value: FieldUpdateValue{Kind: FieldUpdateValueKindString, Null: true, String: &text}, wantErr: "null value cannot carry"},
		{name: "malformed decimal", value: FieldUpdateValue{Kind: FieldUpdateValueKindDecimal, Decimal: &Decimal{Coefficient: "1.20", Scale: 2}}, wantErr: "not canonical"},
		{name: "malformed date", value: FieldUpdateValue{Kind: FieldUpdateValueKindDate, Date: &badDate}, wantErr: "YYYY-MM-DD"},
		{name: "malformed datetime", value: FieldUpdateValue{Kind: FieldUpdateValueKindDateTime, DateTime: &badDateTime}, wantErr: "RFC3339"},
		{name: "empty reference", value: FieldUpdateValue{Kind: FieldUpdateValueKindReference, Reference: &emptyReference}, wantErr: "use Null"},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			err := test.value.Validate()
			if err == nil || !strings.Contains(err.Error(), test.wantErr) {
				t.Fatalf("Validate() error = %v, want containing %q", err, test.wantErr)
			}
		})
	}
}
