package attributes

import (
	"errors"
	"fmt"
	"strings"

	"github.com/nspcc-dev/neofs-sdk-go/netmap"
)

const keyValueSeparator = ":"

// ReadNodeAttributes parses node attributes from list of string in "Key:Value" format
// and writes them into netmap.NodeInfo instance. Supports escaped symbols
// "\:", "\/" and "\\".
func ReadNodeAttributes(dst *netmap.NodeInfo, attrs []string) error {
	cache := make(map[string]struct{}, len(attrs))

	for i := range attrs {
		line := replaceEscaping(attrs[i], false) // replaced escaped symbols with non-printable symbols

		words := strings.Split(line, keyValueSeparator)
		if len(words) != 2 {
			return errors.New("missing attribute key and/or value")
		}

		_, ok := cache[words[0]]
		if ok {
			return fmt.Errorf("duplicated keys %s", words[0])
		}

		cache[words[0]] = struct{}{}

		// replace non-printable symbols with escaped symbols without escape character
		words[0] = replaceEscaping(words[0], true)
		words[1] = replaceEscaping(words[1], true)

		if words[0] == "" {
			return errors.New("empty key")
		} else if words[1] == "" {
			return errors.New("empty value")
		}

		dst.SetAttribute(words[0], words[1])
	}

	return nil
}

func replaceEscaping(target string, rollback bool) (s string) {
	const escChar = `\`

	var (
		oldKVSep = escChar + keyValueSeparator
		oldEsc   = escChar + escChar
		newKVSep = string(uint8(2))
		newEsc   = string(uint8(3))
	)

	if rollback {
		oldKVSep, oldEsc = newKVSep, newEsc
		newKVSep = keyValueSeparator
		newEsc = escChar
	}

	s = strings.ReplaceAll(target, oldEsc, newEsc)
	s = strings.ReplaceAll(s, oldKVSep, newKVSep)

	return
}