package eprel import ( "encoding/json" "fmt" "strconv" "strings" ) var eprelIDKeys = []string{ "eprel_id", "EPRELID", "eprelId", "EprelId", "eprelID", } // NormalizeID coerces XML/API values (string, number, {"#text": ...}) to a trimmed ID. func NormalizeID(v any) string { if v == nil { return "" } switch t := v.(type) { case string: return strings.TrimSpace(t) case json.Number: s := strings.TrimSpace(t.String()) if i := strings.IndexByte(s, '.'); i >= 0 { s = s[:i] } return s case float64: if t != t { // NaN return "" } return strconv.FormatInt(int64(t), 10) case float32: return strconv.FormatInt(int64(t), 10) case int: return strconv.Itoa(t) case int64: return strconv.FormatInt(t, 10) case int32: return strconv.FormatInt(int64(t), 10) case json.RawMessage: var decoded any if err := json.Unmarshal(t, &decoded); err != nil { return "" } return NormalizeID(decoded) case map[string]any: if text, ok := t["#text"]; ok { return NormalizeID(text) } if text, ok := t["text"]; ok { return NormalizeID(text) } default: s := strings.TrimSpace(fmt.Sprint(t)) if s == "" || s == "" { return "" } return s } return "" } // IsValidID reports whether v normalizes to a non-empty EPREL registration id. func IsValidID(v any) bool { return NormalizeID(v) != "" } // ExtractID finds an EPREL ID in mapped and/or raw product field maps // (vendor feeds often use / eprel_id). func ExtractID(sources ...map[string]any) string { for _, src := range sources { if src == nil { continue } for _, key := range eprelIDKeys { if id := NormalizeID(src[key]); id != "" { return id } } for key, value := range src { compact := strings.ToLower(strings.ReplaceAll(key, "_", "")) if compact == "eprelid" { if id := NormalizeID(value); id != "" { return id } } } } return "" }