package reflectext

import "testing"

type TestStruct struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func TestAccessStructByArrayPath_HappyPath(t *testing.T) {
	testStruct := TestStruct{Name: "John", Age: 30}
	result, err := AccessStructByArrayPath[string](testStruct, []string{"Name"})
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "John" {
		t.Errorf("Expected 'John', got '%s'", result)
	}
}

func TestAccessStructByArrayPath_InvalidField(t *testing.T) {
	testStruct := TestStruct{Name: "John", Age: 30}
	_, err := AccessStructByArrayPath[string](testStruct, []string{"Invalid"})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

func TestAccessStructByStringPath_HappyPath(t *testing.T) {
	testStruct := TestStruct{Name: "John", Age: 30}
	result, err := AccessStructByStringPath[string](testStruct, "Name")
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "John" {
		t.Errorf("Expected 'John', got '%s'", result)
	}
}

func TestAccessStructByStringPath_InvalidField(t *testing.T) {
	testStruct := TestStruct{Name: "John", Age: 30}
	_, err := AccessStructByStringPath[string](testStruct, "Invalid")
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

type RecursiveStruct struct {
	Name     string
	Sub      *RecursiveStruct
	SubSlice []RecursiveStruct
}

func TestAccessStructByArrayPath_RecursiveStruct(t *testing.T) {
	testStruct := RecursiveStruct{Name: "John", Sub: &RecursiveStruct{Name: "Jane"}}
	result, err := AccessStructByArrayPath[string](*testStruct.Sub, []string{"Name"})
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "Jane" {
		t.Errorf("Expected 'Jane', got '%s'", result)
	}
}

func TestAccessStructByArrayPath_RecursiveStructSlice(t *testing.T) {
	testStruct := RecursiveStruct{Name: "John", SubSlice: []RecursiveStruct{{Name: "Jane"}}}
	result, err := AccessStructByArrayPath[string](testStruct.SubSlice[0], []string{"Name"})
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "Jane" {
		t.Errorf("Expected 'Jane', got '%s'", result)
	}
}

func TestAccessStructByArrayPath_WrongType(t *testing.T) {
	testStruct := TestStruct{Name: "John", Age: 30}
	_, err := AccessStructByArrayPath[int](testStruct, []string{"Name"})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

func TestAccessStructByArrayPath_InvalidPath(t *testing.T) {
	testStruct := TestStruct{Name: "John", Age: 30}
	_, err := AccessStructByArrayPath[string](testStruct, []string{"Name", "Invalid"})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

type NestedStruct struct {
	Name string
	Sub  *TestStruct
}

func TestAccessStructByStringPath_NestedStruct(t *testing.T) {
	testStruct := NestedStruct{Name: "John", Sub: &TestStruct{Name: "Jane", Age: 30}}
	result, err := AccessStructByStringPath[string](testStruct, "Sub.Name")
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "Jane" {
		t.Errorf("Expected 'Jane', got '%s'", result)
	}
}

type DeepNestedStruct struct {
	Name string
	Sub  *NestedStruct
}

func TestAccessStructByStringPath_DeepNestedStruct(t *testing.T) {
	testStruct := DeepNestedStruct{Name: "John", Sub: &NestedStruct{Name: "Jane", Sub: &TestStruct{Name: "Doe", Age: 30}}}
	result, err := AccessStructByStringPath[string](testStruct, "Sub.Sub.Name")
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "Doe" {
		t.Errorf("Expected 'Doe', got '%s'", result)
	}
}

type MapStruct struct {
	Name string
	Age  int
}

type TestStructWithMap struct {
	MapField map[string]MapStruct
}

func TestAccessStructByArrayPath_MapField(t *testing.T) {
	testStruct := TestStructWithMap{
		MapField: map[string]MapStruct{
			"key": {Name: "John", Age: 30},
		},
	}
	result, err := AccessStructByArrayPath[string](testStruct, []string{"MapField", "key", "Name"})
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "John" {
		t.Errorf("Expected 'John', got '%s'", result)
	}
}

func TestAccessStructByArrayPath_InvalidMapKey(t *testing.T) {
	testStruct := TestStructWithMap{
		MapField: map[string]MapStruct{
			"key": {Name: "John", Age: 30},
		},
	}
	_, err := AccessStructByArrayPath[string](testStruct, []string{"MapField", "invalid", "Name"})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

type ArrayStruct struct {
	Name string
	Arr  []TestStruct
}

func TestAccessStructByArrayPath_ArrayField(t *testing.T) {
	testStruct := ArrayStruct{
		Name: "John",
		Arr:  []TestStruct{{Name: "Jane", Age: 30}},
	}
	result, err := AccessStructByArrayPath[string](testStruct, []string{"Arr", "0", "Name"})
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "Jane" {
		t.Errorf("Expected 'Jane', got '%s'", result)
	}
}

func TestAccessStructByArrayPath_InvalidArrayIndex(t *testing.T) {
	testStruct := ArrayStruct{
		Name: "John",
		Arr:  []TestStruct{{Name: "Jane", Age: 30}},
	}
	_, err := AccessStructByArrayPath[string](testStruct, []string{"Arr", "1", "Name"})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

type FunctionStruct struct {
	Name string
	Func func() string
}

func TestAccessStructByArrayPath_FunctionField(t *testing.T) {
	testStruct := FunctionStruct{Name: "John", Func: func() string { return "Hello" }}
	_, err := AccessStructByArrayPath[string](testStruct, []string{"Func"})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

func TestAccessStructByArrayPath_NonExistentPath(t *testing.T) {
	testStruct := TestStruct{Name: "John", Age: 30}
	_, err := AccessStructByArrayPath[string](testStruct, []string{"NonExistent"})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

type NestedStructWithTag struct {
	Name string      `json:"name"`
	Sub  *TestStruct `json:"sub"`
}

func TestAccessStructByArrayPath_UsedTagForKeys(t *testing.T) {
	testStruct := NestedStructWithTag{Name: "John", Sub: &TestStruct{Name: "Jane", Age: 30}}
	tag := "json"
	result, err := AccessStructByArrayPath[string](testStruct, []string{"sub", "name"}, AccessStructOpt{UsedTagForKeys: &tag})
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != "Jane" {
		t.Errorf("Expected 'Jane', got '%s'", result)
	}
}

func TestAccessStructByArrayPath_UsedTagForKeysInvalid(t *testing.T) {
	testStruct := NestedStructWithTag{Name: "John", Sub: &TestStruct{Name: "Jane", Age: 30}}
	tag := "json"
	_, err := AccessStructByArrayPath[string](testStruct, []string{"sub", "invalid"}, AccessStructOpt{UsedTagForKeys: &tag})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}

type DifferentTypeStruct struct {
	Name string
	Age  int
}

func TestAccessStructByArrayPath_DifferentType(t *testing.T) {
	testStruct := DifferentTypeStruct{Name: "John", Age: 30}
	result, err := AccessStructByArrayPath[any](testStruct, []string{"Age"})
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if result != 30 {
		t.Errorf("Expected '30', got '%v'", result)
	}
}

func TestAccessStructByArrayPath_DifferentTypeInvalid(t *testing.T) {
	testStruct := DifferentTypeStruct{Name: "John", Age: 30}
	_, err := AccessStructByArrayPath[any](testStruct, []string{"Invalid"})
	if err == nil {
		t.Errorf("Expected error, got nil")
	}
}