package utils

import (
	"fmt"
	"reflect"
	"strings"
)

func MergeJSONObjects(dst, src map[string]interface{}) map[string]interface{} {

	result := make(map[string]interface{})
	for k, v := range dst {
		result[k] = v
	}

	for key, value2 := range src {
		value1, exists := result[key]

		if exists {
			map1Val, map1IsMap := value1.(map[string]interface{})
			map2Val, map2IsMap := value2.(map[string]interface{})

			if map1IsMap && map2IsMap {
				result[key] = MergeJSONObjects(map1Val, map2Val)
			} else {
				// 覆盖第一个map中的值
				result[key] = value2
			}
		} else {
			// 添加新的键值对
			result[key] = value2
		}
	}

	return result
}

func StructToMap(in interface{}) (map[string]interface{}, error) {
	out := make(map[string]interface{})

	v := reflect.ValueOf(in)
	// If it's a pointer, dereference it
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	// Check if it's a struct
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("StructToMap only accepts structs or pointers to structs; got %T", v.Interface())
	}

	t := v.Type() // Get the type of the struct
	for i := 0; i < v.NumField(); i++ {
		// Get the field Value and Type
		fieldV := v.Field(i)
		fieldT := t.Field(i)

		// Skip unexported fields
		if !fieldT.IsExported() {
			continue
		}

		// --- Handle JSON Tag ---
		tag := fieldT.Tag.Get("json")
		key := fieldT.Name // Default key is the field name
		omitempty := false

		if tag != "" {
			parts := strings.Split(tag, ",")
			tagName := parts[0]

			if tagName == "-" {
				// Skip fields tagged with "-"
				continue
			}
			if tagName != "" {
				key = tagName // Use tag name as key
			}

			// Check for omitempty option
			for _, part := range parts[1:] {
				if part == "omitempty" {
					omitempty = true
					break
				}
			}
		}

		// --- Handle omitempty ---
		val := fieldV.Interface()
		if omitempty && fieldV.IsZero() {
			continue // Skip zero-value fields if omitempty is set
		}

		// --- Handle Nested Structs/Pointers to Structs (Recursion) ---
		// Check for pointer first
		if fieldV.Kind() == reflect.Ptr {
			// If pointer is nil and omitempty is set, it was already skipped
			// If pointer is nil and omitempty is not set, add nil to map
			if fieldV.IsNil() {
				// Only add nil if omitempty is not set (already handled above)
				if !omitempty {
					out[key] = nil
				}
				continue // Move to next field
			}
			// If it points to a struct, dereference and recurse
			if fieldV.Elem().Kind() == reflect.Struct {
				nestedMap, err := StructToMap(fieldV.Interface()) // Pass the pointer
				if err != nil {
					// Decide how to handle nested errors, e.g., log or return
					fmt.Printf("Warning: could not convert nested struct pointer %s: %v\n", fieldT.Name, err)
					out[key] = val // Store original value on error? Or skip?
				} else {
					out[key] = nestedMap
				}
				continue // Move to next field after handling pointer
			}
			// If pointer to non-struct, just get the interface value (handled below)
			val = fieldV.Interface() // Use the actual pointer value

		} else if fieldV.Kind() == reflect.Struct {
			// If it's a struct (not a pointer), recurse
			nestedMap, err := StructToMap(fieldV.Interface()) // Pass the struct value
			if err != nil {
				fmt.Printf("Warning: could not convert nested struct %s: %v\n", fieldT.Name, err)
				out[key] = val // Store original value on error? Or skip?
			} else {
				out[key] = nestedMap
			}
			continue // Move to next field after handling struct
		}

		// Assign the value (primitive, slice, map, non-struct pointer, etc.)
		out[key] = val
	}

	return out, nil
}
