package attributes

import (
	"errors"
	"fmt"
	"strings"

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

const (
	pairSeparator     = "/"
	keyValueSeparator = ":"
)

var (
	errEmptyChain      = errors.New("empty attribute chain")
	errNonUniqueBucket = errors.New("attributes must contain unique keys")
	errUnexpectedKey   = errors.New("attributes contain unexpected key")
)

// ParseV2Attributes parses strings like "K1:V1/K2:V2/K3:V3" into netmap
// attributes.
func ParseV2Attributes(attrs []string, excl []string) ([]*netmap.NodeAttribute, error) {
	restricted := make(map[string]struct{}, len(excl))
	for i := range excl {
		restricted[excl[i]] = struct{}{}
	}

	cache := make(map[string]*netmap.NodeAttribute, len(attrs))

	for i := range attrs {
		line := strings.Trim(attrs[i], pairSeparator)
		chain := strings.Split(line, pairSeparator)
		if len(chain) == 0 {
			return nil, errEmptyChain
		}

		var parentKey string // backtrack parents in next pairs

		for j := range chain {
			pair := strings.Split(chain[j], keyValueSeparator)
			if len(pair) != 2 {
				return nil, fmt.Errorf("incorrect attribute pair %s", chain[j])
			}

			key := pair[0]
			value := pair[1]

			if at, ok := cache[key]; ok && at.Value() != value {
				return nil, errNonUniqueBucket
			}

			if _, ok := restricted[key]; ok {
				return nil, errUnexpectedKey
			}

			attribute := netmap.NewNodeAttribute()
			attribute.SetKey(key)
			attribute.SetValue(value)

			if parentKey != "" {
				attribute.SetParentKeys(parentKey)
			}

			parentKey = key
			cache[key] = attribute
		}
	}

	result := make([]*netmap.NodeAttribute, 0, len(cache))
	for _, v := range cache {
		result = append(result, v)
	}

	return result, nil
}