func (s *Store) keyNotExist(key string) error {
	if err := s.keyExists(key); err == nil {
		return newKeyErr(ErrKeyExists, key)
	}
	return nil
}
keyExists checks if the key does not exist in the store. Throws an error if it does.
package kiwi
import (
	"encoding/json"
	"fmt"
	"strings"
	"sync"
)
var (
	ErrKeyExists   = fmt.Errorf("key already exists")
	ErrKeyNotExist = fmt.Errorf("key does not exist")
)
func newKeyErr(err error, key string) error {
	return fmt.Errorf("%w: %s", err, key)
}
type Store struct {
	kv map[string]valWrapper
	mu sync.RWMutex
}
func NewStore() *Store {
	return &Store{
		kv: make(map[string]valWrapper),
		mu: sync.RWMutex{},
	}
}
func NewStoreFromSchema(schema Schema) (*Store, error) {
	s := NewStore()
	for key, val := range schema {
		if err := s.AddKey(key, val); err != nil {
			return nil, err
		}
	}
	return s, nil
}
func (s *Store) KeyExists(key string) bool {
	s.mu.RLock()
	exists := s.keyExists(key) == nil
	s.mu.RUnlock()
	return exists
}
func (s *Store) AddKey(key string, typ ValueType) error {
	s.mu.Lock()
	if err := s.keyNotExist(key); err != nil {
		s.mu.Unlock()
		return err
	}
	v, err := newValue(typ)
	if err != nil {
		s.mu.Unlock()
		return err
	}
	s.setValWrapper(key, v)
	s.mu.Unlock()
	return nil
}
func (s *Store) UpdateKey(key string, typ ValueType) error {
	s.mu.Lock()
	if err := s.keyExists(key); err != nil {
		s.mu.Unlock()
		return err
	}
	v, err := newValue(typ)
	if err != nil {
		s.mu.Unlock()
		return err
	}
	old := s.kv[key]
	old.mu.Lock()
	s.setValWrapper(key, v)
	old.mu.Unlock()
	s.mu.Unlock()
	return nil
}
func (s *Store) setValWrapper(key string, val Value) {
	s.kv[key] = valWrapper{
		val:         val,
		mu:          &sync.RWMutex{},
		doMapCached: val.DoMap(),
	}
}
func (s *Store) DeleteKey(key string) error {
	s.mu.Lock()
	if err := s.keyExists(key); err != nil {
		s.mu.Unlock()
		return err
	}
	old := s.kv[key]
	old.mu.Lock()
	delete(s.kv, key)
	old.mu.Unlock()
	s.mu.Unlock()
	return nil
}
func (s *Store) GetValueType(key string) (ValueType, error) {
	s.mu.RLock()
	if err := s.keyExists(key); err != nil {
		s.mu.RUnlock()
		return "", err
	}
	v := s.kv[key]
	s.mu.RUnlock()
	v.mu.RLock()
	typ := v.val.Type()
	v.mu.RUnlock()
	return typ, nil
}
func (s *Store) GetSchema() Schema {
	s.mu.RLock()
	schema := s.getSchema()
	s.mu.RUnlock()
	return schema
}
func (s *Store) getSchema() Schema {
	schema := make(Schema)
	for k := range s.kv {
		schema[k] = s.kv[k].val.Type()
	}
	return schema
}
func (s *Store) Do(key string, action Action, params ...interface{}) (interface{}, error) {
	s.mu.RLock()
	if err := s.keyExists(key); err != nil {
		s.mu.RUnlock()
		return nil, err
	}
	v := s.kv[key]
	s.mu.RUnlock()
	doFunc, ok := v.doMapCached[action]
	if !ok {
		return nil, fmt.Errorf("%w: %v", ErrInvalidAction, action)
	}
	v.mu.Lock()
	res, err := doFunc(params...)
	v.mu.Unlock()
	return res, err
}
func (s *Store) ToJSON(key string) (json.RawMessage, error) {
	s.mu.RLock()
	if err := s.keyExists(key); err != nil {
		s.mu.RUnlock()
		return nil, err
	}
	v := s.kv[key]
	s.mu.RUnlock()
	v.mu.RLock()
	jsonval, err := s.toJSON(&v)
	v.mu.RUnlock()
	return jsonval, err
}
func (s *Store) toJSON(v *valWrapper) (json.RawMessage, error) {
	res, err := v.val.ToJSON()
	if err != nil {
		return nil, fmt.Errorf("error in ToJSON: %v", err)
	}
	return res, nil
}
func (s *Store) FromJSON(key string, rawmessage json.RawMessage) error {
	s.mu.RLock()
	if err := s.keyExists(key); err != nil {
		s.mu.RUnlock()
		return err
	}
	v := s.kv[key]
	s.mu.RUnlock()
	v.mu.Lock()
	err := s.fromJSON(&v, rawmessage)
	v.mu.Unlock()
	return err
}
func (s *Store) fromJSON(v *valWrapper, rawmessage json.RawMessage) error {
	if err := v.val.FromJSON(rawmessage); err != nil {
		return fmt.Errorf("error in FromJSON: %v", err)
	}
	return nil
}
type ValJSON struct {
	Type string          `json:"type"`
	Data json.RawMessage `json:"data"`
}
type StoreJSON = map[string]ValJSON
func (s *Store) Export() (json.RawMessage, error) {
	s.mu.RLock()
	schema := s.getSchema()
	sjson := make(StoreJSON, len(schema))
	for k, v := range schema {
		vw := s.kv[k]
		vw.mu.RLock()
		data, err := s.toJSON(&vw)
		vw.mu.Unlock()
		if err != nil {
			s.mu.RUnlock()
			return nil, fmt.Errorf("error exporting for %q key: %v", k, err)
		}
		sjson[k] = ValJSON{
			Type: string(v),
			Data: data,
		}
	}
	s.mu.RUnlock()
	c, err := json.Marshal(sjson)
	if err != nil {
		return nil, err
	}
	return c, nil
}
type ImportOpts struct {
	AddKeys bool
	UpdateTypes bool
	ErrOnInvalidKey bool
}
func (s *Store) Import(rawmessage json.RawMessage, opts ImportOpts) error {
	var sjson StoreJSON
	if err := json.Unmarshal(rawmessage, &sjson); err != nil {
		return err
	}
	s.mu.Lock()
	for k := range sjson {
		if err := s.keyExists(k); err != nil {
			if !opts.AddKeys && !opts.ErrOnInvalidKey {
				continue
			}
			if !opts.AddKeys && opts.ErrOnInvalidKey {
				s.mu.Unlock()
				return err
			}
			if opts.AddKeys {
				if er := s.AddKey(k, ValueType(sjson[k].Type)); er != nil {
					s.mu.Unlock()
					return er
				}
			}
		}
		v := s.kv[k]
		v.mu.Lock()
		if sjson[k].Type != string(v.val.Type()) {
			if !opts.UpdateTypes {
				v.mu.Unlock()
				s.mu.Unlock()
				return fmt.Errorf("value type in JSON and store schema do not match")
			}
			if er := s.UpdateKey(k, ValueType(sjson[k].Type)); er != nil {
				v.mu.Unlock()
				s.mu.Unlock()
				return er
			}
		}
		if err := s.FromJSON(k, sjson[k].Data); err != nil {
			v.mu.Unlock()
			s.mu.Unlock()
			return err
		}
		v.mu.Unlock()
	}
	s.mu.Unlock()
	return nil
}
func (s *Store) keyExists(key string) error {
	if _, ok := s.kv[key]; !ok {
		return newKeyErr(ErrKeyNotExist, key)
	}
	return nil
}