package engine

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/stretchr/testify/require"
)

// TestMapKeyToString tests the functions [MapKeyToString()] and all the methods called by them
func TestMapKeyToString(t *testing.T) {
	testCases := []struct {
		payload  interface{}
		expected string
	}{
		{
			payload:  "test",
			expected: "test",
		},
		{
			payload:  123,
			expected: "123",
		},
		{
			payload:  0.123,
			expected: "0.123",
		},
		{
			payload:  false,
			expected: "false",
		},
		{
			payload:  nil,
			expected: "null",
		},
	}

	for i, testCase := range testCases {
		t.Run(fmt.Sprintf("mapKeyToString-%d", i), func(t *testing.T) {
			v, err := mapKeyToString(map[string]interface{}{"key": testCase.payload}, "key", false)
			require.Nil(t, err)
			require.Equal(t, testCase.expected, *v)
		})
	}
	for i, testCase := range testCases {
		t.Run(fmt.Sprintf("mapKeyToString-%d", i), func(t *testing.T) {
			_, err := mapKeyToString(map[string]interface{}{"t": testCase.payload}, "key", false)
			require.Error(t, err)
		})
	}
}

// Test_mergeWithMetadata tests the functions [mergeWithMetadata()] and all the methods called by them
func Test_mergeWithMetadata(t *testing.T) {
	type args struct {
		base       map[string]interface{}
		additional map[string]interface{}
	}
	tests := []struct {
		name string
		args args
		want map[string]interface{}
	}{
		{
			name: "mergeWithMetadata",
			args: args{
				base: map[string]interface{}{
					"key": "123",
				},
				additional: map[string]interface{}{
					"key": "teste",
				},
			},
			want: map[string]interface{}{
				"key": "123",
			},
		},
		{
			name: "mergeWithMetadata_2",
			args: args{
				base: map[string]interface{}{
					"key": "123",
				},
				additional: map[string]interface{}{
					"r": "teste2",
				},
			},
			want: map[string]interface{}{
				"key": "123",
				"r":   "teste2",
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := mergeWithMetadata(tt.args.base, tt.args.additional); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("mergeWithMetadata() = %v, want %v", got, tt.want)
			}
		})
	}
}

// Test_mustMapKeyToString tests the functions [mustMapKeyToString()] and all the methods called by them
func Test_mustMapKeyToString(t *testing.T) {
	type args struct {
		m   map[string]interface{}
		key string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "mustMapKeyToString",
			args: args{
				m: map[string]interface{}{
					"key": 123,
				},
				key: "key",
			},
			want: "123",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := mustMapKeyToString(tt.args.m, tt.args.key)
			require.Equal(t, tt.want, *got)
		})
	}
}

// Test_ptrStringToString tests the functions [ptrStringToString()] and all the methods called by them
func Test_PtrStringToString(t *testing.T) {
	type args struct {
		v string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "PtrStringToString",
			args: args{
				v: "123",
			},
			want: "123",
		},
		{
			name: "PtrStringToString_empty",
			args: args{
				v: "nil",
			},
			want: "",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if tt.args.v == "nil" {
				if got := PtrStringToString(nil); got != tt.want {
					t.Errorf("PtrStringToString() = %v, want %v", got, tt.want)
				}
			} else {
				if got := PtrStringToString(&tt.args.v); got != tt.want {
					t.Errorf("PtrStringToString() = %v, want %v", got, tt.want)
				}
			}
		})
	}
}
