package utils

import "strconv"

// MergeMaps takes two maps <base>, <overlay> and merges them. If <overlay> defines a value with a key
// already existing in the <base> map, the <base> value for that key will be overwritten.
func MergeMaps(base, overlay map[string]interface{}) map[string]interface{} {
	var values = map[string]interface{}{}

	for i, v := range overlay {
		existing, ok := base[i]
		values[i] = v

		switch elem := v.(type) {
		case map[string]interface{}:
			if ok {
				if extMap, ok := existing.(map[string]interface{}); ok {
					values[i] = MergeMaps(extMap, elem)
				}
			}
		default:
			values[i] = v
		}
	}

	for i, v := range base {
		if _, ok := values[i]; !ok {
			values[i] = v
		}
	}

	return values
}

// FlattenMap flatten a possible nested map to a shallow one which has at most one layer,
// nested keys are concated with `.`
func FlattenMap(m map[string]interface{}) map[string]interface{} {
	res := make(map[string]interface{})
	doFlattenMap("", m, res)
	return res
}

func doFlattenMap(prefix string, src map[string]interface{}, dest map[string]interface{}) {
	if len(prefix) > 0 {
		prefix += "."
	}
	for k, v := range src {
		switch child := v.(type) {
		case map[string]interface{}:
			doFlattenMap(prefix+k, child, dest)
		case []interface{}:
			for i := 0; i < len(child); i++ {
				dest[prefix+k+"."+strconv.Itoa(i)] = child[i]
			}
		default:
			dest[prefix+k] = v
		}
	}
}

func DefaultIfEmpty(v *string, defaultValue string) string {
	if v == nil {
		return defaultValue
	}
	return *v
}
