package storage

import (
	"fmt"
	"sync"
)

type Map struct {
	m    map[string]map[string][]byte
	lock *sync.RWMutex
}

func NewMap() *Map {
	return &Map{
		m:    make(map[string]map[string][]byte),
		lock: &sync.RWMutex{},
	}
}

func (m *Map) String() string {
	m.lock.RLock()
	defer m.lock.RUnlock()
	s := ""
	for k, v := range m.m {
		if s != "" {
			s += ",\n"
		}
		s += fmt.Sprintf("[%s]:[%s]", k, v)
	}
	return s
}

func (m *Map) Close() error {
	m.lock.Lock()
	defer m.lock.Unlock()
	m.m = nil
	return nil
}

func (m *Map) List(ns []string, limits ...string) ([]string, error) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	namespace := resolveNamespace(ns)
	limits = resolveLimits(limits)

	keys := []string{}
	if _, ok := m.m[namespace]; !ok {
		namespace = DefaultNamespace
	}
	for k := range m.m[namespace] {
		if k >= limits[0] && k <= limits[1] {
			keys = append(keys, k)
		}
	}

	return keys, nil
}

func (m *Map) Get(key string, ns ...string) ([]byte, error) {
	m.lock.RLock()
	defer m.lock.RUnlock()
	namespace := resolveNamespace(ns)
	if _, ok := m.m[namespace]; !ok {
		return nil, ErrNotFound
	}
	if _, ok := m.m[namespace][key]; !ok {
		return nil, ErrNotFound
	}
	return m.m[namespace][key], nil
}

func (m *Map) Set(key string, value []byte, ns ...string) error {
	m.lock.Lock()
	defer m.lock.Unlock()
	namespace := resolveNamespace(ns)
	if value == nil {
		if _, ok := m.m[namespace]; !ok {
			return nil
		} else if _, ok := m.m[namespace][key]; ok {
			delete(m.m[namespace], key)
		}
	} else {
		if _, ok := m.m[namespace]; !ok {
			m.m[namespace] = make(map[string][]byte)
		}
		m.m[namespace][key] = value
	}
	return nil
}
