package server

import (
	"fmt"
	"sync"

	"code.secondbit.org/feature.hg"
)

const (
	errNotFound      = "flag not found"
	errAlreadyExists = "flag already exists"
)

type flagError struct {
	pos  int
	code string
}

func (f *flagError) Error() string {
	return fmt.Sprintf("[%d]: %s", f.pos, f.code)
}

type flagStore interface {
	create(f feature.Flag) *flagError
	update(flags []feature.Flag) []flagError
	destroy(flag string) *flagError
	list() ([]feature.Flag, *flagError)
}

type memstore struct {
	flags map[string]feature.Flag
	flock sync.RWMutex
}

func (m *memstore) create(f feature.Flag) *flagError {
	m.flock.Lock()
	defer m.flock.Unlock()

	if _, ok := m.flags[f.ID]; ok {
		return &flagError{pos: 0, code: errNotFound}
	}
	m.flags[f.ID] = f
	return nil
}

func (m *memstore) update(flags []feature.Flag) []flagError {
	m.flock.Lock()
	defer m.flock.Unlock()

	errs := []flagError{}
	for pos, f := range flags {
		if _, ok := m.flags[f.ID]; !ok {
			errs = append(errs, flagError{pos: pos, code: errNotFound})
		}
	}
	if len(errs) > 0 {
		return errs
	}
	for _, flag := range flags {
		m.flags[flag.ID] = flag
	}
	return nil
}

func (m *memstore) destroy(flag string) *flagError {
	m.flock.Lock()
	defer m.flock.Unlock()

	if _, ok := m.flags[flag]; !ok {
		return &flagError{pos: 0, code: errNotFound}
	}
	delete(m.flags, flag)
	return nil
}

func (m *memstore) list() ([]feature.Flag, *flagError) {
	m.flock.RLock()
	defer m.flock.RUnlock()

	flags := make([]feature.Flag, len(m.flags))
	pos := 0
	for _, flag := range m.flags {
		flags[pos] = flag
		pos = pos + 1
	}
	return flags, nil
}
