package browser

import (
	"regexp"
	"strings"
	"sync"
)

const defaultMaxRefStoreSize = 50

var refPattern = regexp.MustCompile(`^e\d+$`)

// RefStore is a thread-safe, per-tab LRU cache for snapshot refs.
// Each entry maps a targetID to its ref→RoleRef mapping from the last snapshot.
type RefStore struct {
	mu      sync.RWMutex
	entries map[string]map[string]RoleRef
	order   []string // LRU order (most recently used at end)
	maxSize int
}

// NewRefStore creates a RefStore with default capacity.
func NewRefStore() *RefStore {
	return &RefStore{
		entries: make(map[string]map[string]RoleRef),
		maxSize: defaultMaxRefStoreSize,
	}
}

// Store saves refs for a target, evicting oldest entries if over capacity.
func (rs *RefStore) Store(targetID string, refs map[string]RoleRef) {
	rs.mu.Lock()
	defer rs.mu.Unlock()

	// Remove from current position in LRU order
	rs.removeFromOrder(targetID)

	// Add to end (most recently used)
	rs.order = append(rs.order, targetID)
	rs.entries[targetID] = refs

	// Evict oldest if over capacity
	for len(rs.order) > rs.maxSize {
		oldest := rs.order[0]
		rs.order = rs.order[1:]
		delete(rs.entries, oldest)
	}
}

// Resolve looks up a ref for a given target.
func (rs *RefStore) Resolve(targetID, ref string) (*RoleRef, bool) {
	rs.mu.RLock()
	defer rs.mu.RUnlock()

	normalized := NormalizeRef(ref)
	refs, ok := rs.entries[targetID]
	if !ok {
		return nil, false
	}
	r, ok := refs[normalized]
	if !ok {
		return nil, false
	}
	return &r, true
}

// NormalizeRef normalizes ref formats: "@e5", "ref=e5", "e5" → "e5".
func NormalizeRef(raw string) string {
	s := strings.TrimSpace(raw)
	if s == "" {
		return ""
	}
	if strings.HasPrefix(s, "@") {
		s = s[1:]
	} else if strings.HasPrefix(s, "ref=") {
		s = s[4:]
	}
	if refPattern.MatchString(s) {
		return s
	}
	return s
}

func (rs *RefStore) removeFromOrder(targetID string) {
	for i, id := range rs.order {
		if id == targetID {
			rs.order = append(rs.order[:i], rs.order[i+1:]...)
			return
		}
	}
}
