package validators

import (
	"strings"
	"testing"
)

type validatorSample struct {
	Email string `json:"email" validate:"required,email"`
	Name  string `json:"name" validate:"required"`
}

type validatorTagNameSample struct {
	NoTag string `validate:"required"`
	Nick  string `json:"nick,omitempty" validate:"required"`
}

func TestNew(t *testing.T) {
	v := New()
	if v == nil || v.validate == nil {
		t.Fatalf("expected validator instance")
	}
}

type hoursOrDateSample struct {
	Due string `json:"due" validate:"omitempty,hours_or_date"`
}

func TestHoursOrDateValidation(t *testing.T) {
	cases := []struct {
		in    string
		valid bool
	}{
		{"", true},
		{"1200", true},
		{"1200.5", true},
		{"2026-06-17", true},
		{"1200 FH", false},
		{"1200FH", false},
		{"FH", false},
		{"17-06-2026", false},
		{"abc", false},
		{"-5", false},
	}
	v := New()
	for _, tc := range cases {
		t.Run(tc.in, func(t *testing.T) {
			errs := v.ValidateStruct(hoursOrDateSample{Due: tc.in})
			if tc.valid && errs != nil {
				t.Fatalf("%q should be valid, got %+v", tc.in, errs)
			}
			if !tc.valid && errs == nil {
				t.Fatalf("%q should be rejected", tc.in)
			}
		})
	}
}

func TestValidateStruct(t *testing.T) {
	t.Run("valid struct", func(t *testing.T) {
		v := New()
		errs := v.ValidateStruct(validatorSample{Email: "user@example.com", Name: "John"})
		if errs != nil {
			t.Fatalf("expected nil errors, got %+v", errs)
		}
	})

	t.Run("validation errors converted to jsonapi", func(t *testing.T) {
		v := New()
		errs := v.ValidateStruct(validatorSample{Email: "invalid", Name: ""})
		if len(errs) < 2 {
			t.Fatalf("expected at least 2 validation errors, got %+v", errs)
		}
		for _, e := range errs {
			if e.Status != "422" {
				t.Fatalf("expected status 422, got %q", e.Status)
			}
			if e.Title != "Validation error" {
				t.Fatalf("expected validation title, got %q", e.Title)
			}
			if e.Source == nil || !strings.HasPrefix(e.Source.Pointer, "/data/attributes/") {
				t.Fatalf("expected jsonapi pointer, got %+v", e.Source)
			}
		}
	})

	t.Run("non validation error", func(t *testing.T) {
		v := New()
		errs := v.ValidateStruct(123)
		if len(errs) != 1 {
			t.Fatalf("expected single error, got %+v", errs)
		}
		if errs[0].Status != "400" || errs[0].Title != "Invalid request" {
			t.Fatalf("unexpected error object: %+v", errs[0])
		}
	})

	t.Run("tag name resolver handles empty and comma json tags", func(t *testing.T) {
		v := New()
		errs := v.ValidateStruct(validatorTagNameSample{})
		if len(errs) != 2 {
			t.Fatalf("expected 2 validation errors, got %+v", errs)
		}

		var seenNoTag bool
		var seenNick bool
		for _, e := range errs {
			if strings.Contains(e.Detail, "NoTag is required") && e.Source != nil && e.Source.Pointer == "/data/attributes/NoTag" {
				seenNoTag = true
			}
			if strings.Contains(e.Detail, "nick is required") && e.Source != nil && e.Source.Pointer == "/data/attributes/nick" {
				seenNick = true
			}
		}
		if !seenNoTag || !seenNick {
			t.Fatalf("expected errors for NoTag and nick fields, got %+v", errs)
		}
	})
}
