package trie

import (
	"slices"
	"strings"

	"github.com/yusing/go-proxy/internal/utils/strutils"
)

type Key struct {
	segments    []string // escaped segments
	full        string   // unescaped original key
	hasWildcard bool
}

func Namespace(ns string) *Key {
	return &Key{
		segments:    []string{ns},
		full:        ns,
		hasWildcard: false,
	}
}

func NewKey(keyStr string) *Key {
	key := &Key{
		segments: strutils.SplitRune(keyStr, '.'),
		full:     keyStr,
	}
	for _, seg := range key.segments {
		if seg == "*" || seg == "**" {
			key.hasWildcard = true
		}
	}
	return key
}

func EscapeSegment(seg string) string {
	var sb strings.Builder
	for _, r := range seg {
		switch r {
		case '.', '*':
			sb.WriteString("__")
		default:
			sb.WriteRune(r)
		}
	}
	return sb.String()
}

func (ns Key) With(segment string) *Key {
	ns.segments = append(ns.segments, segment)
	ns.full = ns.full + "." + segment
	ns.hasWildcard = ns.hasWildcard || segment == "*" || segment == "**"
	return &ns
}

func (ns Key) WithEscaped(segment string) *Key {
	ns.segments = append(ns.segments, EscapeSegment(segment))
	ns.full = ns.full + "." + segment
	return &ns
}

func (ns *Key) NumSegments() int {
	return len(ns.segments)
}

func (ns *Key) HasWildcard() bool {
	return ns.hasWildcard
}

func (ns *Key) String() string {
	return ns.full
}

func (ns *Key) Clone() *Key {
	clone := *ns
	clone.segments = slices.Clone(ns.segments)
	clone.full = strings.Clone(ns.full)
	return &clone
}