package utils

import (
	"strings"
)

type MultiIndex[T any] struct {
	items   []T
	indexes []map[string]*T
}

func NewMultiIndex[T any](numIndexes int) *MultiIndex[T] {
	m := &MultiIndex[T]{
		items:   make([]T, 0),
		indexes: make([]map[string]*T, numIndexes),
	}
	for i := range m.indexes {
		m.indexes[i] = make(map[string]*T)
	}
	return m
}

func (m *MultiIndex[T]) AddItem(item T, searchKeys [][]string) {
	if len(searchKeys) != len(m.indexes) {
		panic("searchKeys length must match number of indexes")
	}

	m.items = append(m.items, item)
	itemPtr := &m.items[len(m.items)-1]

	for i, key := range searchKeys {
		m.indexes[i][keyToString(key)] = itemPtr
	}
}

func (m *MultiIndex[T]) FindItem(indexNum int, key []string) (T, bool) {
	var zero T
	if indexNum < 0 || indexNum >= len(m.indexes) {
		return zero, false
	}

	itemPtr, found := m.indexes[indexNum][keyToString(key)]
	if !found {
		return zero, false
	}
	return *itemPtr, true
}

func (m *MultiIndex[T]) Items() []T {
	result := make([]T, len(m.items))
	copy(result, m.items)
	return result
}

func keyToString(parts []string) string {
	return strings.Join(parts, "\x00")
}
