package core

import (
	"strings"
	"testing"
)

func TestValidateStructFields(t *testing.T) {
	t.Run("campo required presente y ausente", func(t *testing.T) {
		rules := map[string]string{"name": "required"}

		valid, errs := ValidateStructFields(map[string]any{"name": "Alice"}, rules)
		if !valid || len(errs) != 0 {
			t.Errorf("expected valid, got errors: %v", errs)
		}

		valid2, errs2 := ValidateStructFields(map[string]any{}, rules)
		if valid2 || len(errs2) == 0 {
			t.Errorf("expected invalid for missing required field")
		}
	})

	t.Run("type validation string como int falla", func(t *testing.T) {
		rules := map[string]string{"count": "type=int"}

		valid, _ := ValidateStructFields(map[string]any{"count": 5}, rules)
		if !valid {
			t.Error("expected int 5 to pass type=int")
		}

		valid2, errs2 := ValidateStructFields(map[string]any{"count": "five"}, rules)
		if valid2 || len(errs2) == 0 {
			t.Error("expected string to fail type=int")
		}
	})

	t.Run("numeric ranges", func(t *testing.T) {
		rules := map[string]string{"score": "min=0,max=100"}

		valid, _ := ValidateStructFields(map[string]any{"score": 50}, rules)
		if !valid {
			t.Error("expected 50 to pass min=0,max=100")
		}

		valid2, errs2 := ValidateStructFields(map[string]any{"score": 150}, rules)
		if valid2 || !strings.Contains(errs2[0], "max") {
			t.Errorf("expected max violation, got: %v", errs2)
		}

		valid3, errs3 := ValidateStructFields(map[string]any{"score": -1}, rules)
		if valid3 || !strings.Contains(errs3[0], "min") {
			t.Errorf("expected min violation, got: %v", errs3)
		}
	})

	t.Run("string lengths", func(t *testing.T) {
		rules := map[string]string{"tag": "minlen=2,maxlen=10"}

		valid, _ := ValidateStructFields(map[string]any{"tag": "go"}, rules)
		if !valid {
			t.Error("expected 'go' to pass minlen=2,maxlen=10")
		}

		valid2, errs2 := ValidateStructFields(map[string]any{"tag": "a"}, rules)
		if valid2 || !strings.Contains(errs2[0], "minlen") {
			t.Errorf("expected minlen violation, got: %v", errs2)
		}

		valid3, errs3 := ValidateStructFields(map[string]any{"tag": "averylongtag"}, rules)
		if valid3 || !strings.Contains(errs3[0], "maxlen") {
			t.Errorf("expected maxlen violation, got: %v", errs3)
		}
	})

	t.Run("oneof validation", func(t *testing.T) {
		rules := map[string]string{"status": "oneof=active|inactive|pending"}

		valid, _ := ValidateStructFields(map[string]any{"status": "active"}, rules)
		if !valid {
			t.Error("expected 'active' to pass oneof")
		}

		valid2, errs2 := ValidateStructFields(map[string]any{"status": "deleted"}, rules)
		if valid2 || len(errs2) == 0 {
			t.Errorf("expected oneof violation, got: %v", errs2)
		}
	})

	t.Run("pattern matching", func(t *testing.T) {
		rules := map[string]string{"email": `pattern=^[^@]+@[^@]+\.[^@]+$`}

		valid, _ := ValidateStructFields(map[string]any{"email": "user@example.com"}, rules)
		if !valid {
			t.Error("expected valid email to pass pattern")
		}

		valid2, errs2 := ValidateStructFields(map[string]any{"email": "not-an-email"}, rules)
		if valid2 || !strings.Contains(errs2[0], "pattern") {
			t.Errorf("expected pattern violation, got: %v", errs2)
		}
	})

	t.Run("multiples reglas combinadas", func(t *testing.T) {
		rules := map[string]string{
			"name":  "required,type=string,minlen=2,maxlen=50",
			"score": "required,type=float,min=0,max=10",
		}

		valid, _ := ValidateStructFields(map[string]any{"name": "Alice", "score": float64(8.5)}, rules)
		if !valid {
			t.Error("expected all rules to pass")
		}

		valid2, errs2 := ValidateStructFields(map[string]any{"name": "A", "score": float64(11)}, rules)
		if valid2 || len(errs2) < 2 {
			t.Errorf("expected at least 2 errors, got: %v", errs2)
		}
	})

	t.Run("map vacio con reglas required", func(t *testing.T) {
		rules := map[string]string{
			"id":   "required",
			"name": "required",
		}

		valid, errs := ValidateStructFields(map[string]any{}, rules)
		if valid || len(errs) < 2 {
			t.Errorf("expected 2 required errors, got: %v", errs)
		}
	})
}
