package etcd

import (
	"strings"

	"github.com/asim/go-micro/v3/config/encoder"
	"go.etcd.io/etcd/api/v3/mvccpb"
	"go.etcd.io/etcd/client/v3"
)

func makeEvMap(e encoder.Encoder, data map[string]interface{}, kv []*clientv3.Event, stripPrefix string) map[string]interface{} {
	if data == nil {
		data = make(map[string]interface{})
	}

	for _, v := range kv {
		switch mvccpb.Event_EventType(v.Type) {
		case mvccpb.DELETE:
			data = update(e, data, (*mvccpb.KeyValue)(v.Kv), "delete", stripPrefix)
		default:
			data = update(e, data, (*mvccpb.KeyValue)(v.Kv), "insert", stripPrefix)
		}
	}

	return data
}

func makeMap(e encoder.Encoder, kv []*mvccpb.KeyValue, stripPrefix string) map[string]interface{} {
	data := make(map[string]interface{})

	for _, v := range kv {
		data = update(e, data, v, "put", stripPrefix)
	}

	return data
}

func update(e encoder.Encoder, data map[string]interface{}, v *mvccpb.KeyValue, action, stripPrefix string) map[string]interface{} {
	// remove prefix if non empty, and ensure leading / is removed as well
	vkey := strings.TrimPrefix(strings.TrimPrefix(string(v.Key), stripPrefix), "/")
	// split on prefix
	haveSplit := strings.Contains(vkey, "/")
	keys := strings.Split(vkey, "/")

	var vals interface{}
	e.Decode(v.Value, &vals)

	if !haveSplit && len(keys) == 1 {
		switch action {
		case "delete":
			data = make(map[string]interface{})
		default:
			v, ok := vals.(map[string]interface{})
			if ok {
				data = v
			}
		}
		return data
	}

	// set data for first iteration
	kvals := data
	// iterate the keys and make maps
	for i, k := range keys {
		kval, ok := kvals[k].(map[string]interface{})
		if !ok {
			// create next map
			kval = make(map[string]interface{})
			// set it
			kvals[k] = kval
		}

		// last key: write vals
		if l := len(keys) - 1; i == l {
			switch action {
			case "delete":
				delete(kvals, k)
			default:
				kvals[k] = vals
			}
			break
		}

		// set kvals for next iterator
		kvals = kval
	}

	return data
}
