package utils

import (
	"encoding/json"
	"testing"
)

func TestJSON(t *testing.T) {
	tests := []struct {
		name     string
		input    any
		expected string
	}{
		{
			name:     "nil input",
			input:    nil,
			expected: "null",
		},
		{
			name:     "empty string",
			input:    "",
			expected: `""`,
		},
		{
			name:     "simple string",
			input:    "hello",
			expected: `"hello"`,
		},
		{
			name:     "number",
			input:    123,
			expected: "123",
		},
		{
			name:     "boolean",
			input:    true,
			expected: "true",
		},
		{
			name: "simple map",
			input: map[string]string{
				"key": "value",
			},
			expected: `{"key":"value"}`,
		},
		{
			name: "nested map",
			input: map[string]any{
				"level1": map[string]any{
					"level2": "value",
				},
			},
			expected: `{"level1":{"level2":"value"}}`,
		},
		{
			name:     "slice",
			input:    []string{"a", "b", "c"},
			expected: `["a","b","c"]`,
		},
		{
			name: "struct",
			input: struct {
				Name  string `json:"name"`
				Value int    `json:"value"`
			}{
				Name:  "test",
				Value: 42,
			},
			expected: `{"name":"test","value":42}`,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := JSON(tt.input)
			if result != tt.expected {
				t.Errorf("JSON() = %v, want %v", result, tt.expected)
			}
		})
	}
}

func TestPrettyJSON(t *testing.T) {
	tests := []struct {
		name     string
		input    any
		expected string
	}{
		{
			name:     "nil input",
			input:    nil,
			expected: "null",
		},
		{
			name:     "empty string",
			input:    "",
			expected: `""`,
		},
		{
			name:     "simple string",
			input:    "hello",
			expected: `"hello"`,
		},
		{
			name:     "number",
			input:    123,
			expected: "123",
		},
		{
			name:     "boolean",
			input:    true,
			expected: "true",
		},
		{
			name: "simple map",
			input: map[string]string{
				"key": "value",
			},
			expected: `{
  "key": "value"
}`,
		},
		{
			name: "nested map",
			input: map[string]any{
				"level1": map[string]any{
					"level2": "value",
				},
			},
			expected: `{
  "level1": {
    "level2": "value"
  }
}`,
		},
		{
			name:  "slice",
			input: []string{"a", "b", "c"},
			expected: `[
  "a",
  "b",
  "c"
]`,
		},
		{
			name: "struct",
			input: struct {
				Name  string `json:"name"`
				Value int    `json:"value"`
			}{
				Name:  "test",
				Value: 42,
			},
			expected: `{
  "name": "test",
  "value": 42
}`,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := PrettyJSON(tt.input)
			if result != tt.expected {
				t.Errorf("PrettyJSON() = %v, want %v", result, tt.expected)
			}
		})
	}
}

func TestJSONWithComplexData(t *testing.T) {
	complexData := map[string]any{
		"string":  "test",
		"number":  42,
		"boolean": true,
		"null":    nil,
		"array":   []any{1, "two", false, nil},
		"object": map[string]any{
			"nested": "value",
			"deep": map[string]any{
				"level": 3,
			},
		},
	}

	// Test that JSON() produces valid JSON
	result := JSON(complexData)
	var parsed map[string]any
	err := json.Unmarshal([]byte(result), &parsed)
	if err != nil {
		t.Errorf("JSON() produced invalid JSON: %v", err)
	}

	// Test that PrettyJSON() produces valid JSON
	prettyResult := PrettyJSON(complexData)
	err = json.Unmarshal([]byte(prettyResult), &parsed)
	if err != nil {
		t.Errorf("PrettyJSON() produced invalid JSON: %v", err)
	}
}

func TestJSONWithSpecialCharacters(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "quotes",
			input:    `"quoted"`,
			expected: `"\"quoted\""`,
		},
		{
			name:     "backslash",
			input:    `\backslash\`,
			expected: `"\\backslash\\"`,
		},
		{
			name:     "newline",
			input:    "line1\nline2",
			expected: `"line1\nline2"`,
		},
		{
			name:     "tab",
			input:    "tab\there",
			expected: `"tab\there"`,
		},
		{
			name:     "unicode",
			input:    "中文测试",
			expected: `"中文测试"`,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := JSON(tt.input)
			if result != tt.expected {
				t.Errorf("JSON() = %v, want %v", result, tt.expected)
			}

			// Verify it can be parsed back
			var parsed string
			err := json.Unmarshal([]byte(result), &parsed)
			if err != nil {
				t.Errorf("JSON() produced invalid JSON for %s: %v", tt.name, err)
			}
			if parsed != tt.input {
				t.Errorf("Parsed result = %v, want %v", parsed, tt.input)
			}
		})
	}
}
