package sdk

import (
	"fmt"
	"strings"

	"github.com/pingcap/errors"
)

// Merge apply the overlay struct to the base struct and override the same key.
// Merge will deep merge two maps, overlay will override values in base.
func Merge(base map[string]interface{}, overlay map[string]interface{}, keyPath ...string) error {
	child, err := GetChild(base, keyPath...)
	if err != nil {
		return errors.Wrap(err, "get child")
	}
	for k, v := range overlay {
		switch v := v.(type) {
		case map[string]interface{}:
			if _, ok := child[k]; !ok {
				child[k] = map[string]interface{}{}
			}
			if err := Merge(child, v, k); err != nil {
				return errors.Wrap(err, fmt.Sprintf("error overlay processing key %s", k))
			}
		default:
			child[k] = v
		}
	}
	return nil
}

func GetChild(base map[string]interface{}, keyPath ...string) (map[string]interface{}, error) {
	child := base
	for _, key := range keyPath {
		next, ok := child[key]
		if !ok {
			return nil, errors.New(fmt.Sprintf("key %s not found", strings.Join(keyPath, ".")))
		}
		child, ok = next.(map[string]interface{})
		if !ok {
			return nil, errors.New(fmt.Sprintf("key %s is not an Object", strings.Join(keyPath, ".")))
		}
	}
	return child, nil
}
