// package safe_bool_react -- потокобезопасный булевый признак с реакцией на своё изменение
package safe_bool_react

import (
	"fmt"
	"os"
	"strings"
	"sync"

	. "gitp78su.ipnodns.ru/svi/kern/v3/kc/helpers"
	. "gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
)

// safeBoolReact -- потокобезопасный булевый признак с реакцией на своё изменение
type safeBoolReact struct {
	sync.RWMutex
	dict map[string]func(bool) // Словарь обратных вызовов
	val  bool
}

// NewSafeBoolReact -- возвращает новый потокобезопасный булевый признак с реакцией на своё изменение
func NewSafeBoolReact() ISafeBoolReact {
	sf := &safeBoolReact{
		dict: map[string]func(bool){},
	}
	return sf
}

// NewSafeBoolReactFromStr -- возвращает новое потокобезоппсное булево с реакцией из строки
func NewSafeBoolReactFromStr(strVal string) Result[ISafeBoolReact] {
	sf := NewSafeBoolReact()
	res := sf.FromStr(strVal)
	if res.IsErr() {
		err := fmt.Errorf("NewSafeBoolReactFromStr(): in parse str(%v), err=\n\t%w", strVal, res.Err())
		return NewErr[ISafeBoolReact](err)
	}
	return NewOk(sf)
}

// NewSafeBoolGetenv -- возвращает новое потокобезоппсное целое с реакцией из окружения
func NewSafeBoolGetenv(env string) Result[ISafeBoolReact] {
	sf := NewSafeBoolReact()
	res := sf.Getenv(env)
	if res.IsErr() {
		err := fmt.Errorf("NewSafeBoolGetenv(): in parse env(%v), err=\n\t%w", env, res.Err())
		return NewErr[ISafeBoolReact](err)
	}
	return NewOk(sf)
}

// Delete -- удаляет функцию обратного вызова из наблюдения
func (sf *safeBoolReact) Delete(key string) {
	sf.Lock()
	defer sf.Unlock()
	delete(sf.dict, key)
}

// Add -- добавляет функцию обратного вызова
func (sf *safeBoolReact) Add(key string, fn func(bool)) {
	sf.Lock()
	defer sf.Unlock()
	Hassert(key != "", "safeBoolReact.Add(): key is empty")
	_, isOk := sf.dict[key]
	Hassert(!isOk, "safeBoolReact.Add(): key already exists")
	sf.dict[key] = fn
}

// Get -- возвращает хранимый булевый признак
func (sf *safeBoolReact) Get() bool {
	sf.RLock()
	defer sf.RUnlock()
	return sf.val
}

// Set -- устанавливает булевый признак
func (sf *safeBoolReact) Set() {
	sf.Lock()
	defer sf.Unlock()
	sf.val = true
	for _, fn := range sf.dict {
		fn(true)
	}
}

// Reset -- сбрасывает булевый признак
func (sf *safeBoolReact) Reset() {
	sf.Lock()
	defer sf.Unlock()
	sf.val = false
	for _, fn := range sf.dict {
		fn(false)
	}
}

// FromStr -- получает число из строки
func (sf *safeBoolReact) FromStr(strVal string) Result[bool] {
	strVal = strings.ToLower(strVal)
	sf.Lock()
	defer sf.Unlock()
	switch strVal {
	case "true":
		sf.val = true
	case "false":
		sf.val = false
	default:
		return NewErr[bool](fmt.Errorf("safeBoolReact.FromStr(): val(%v) bad", strVal))
	}
	return NewOk(sf.val)
}

// Getenv -- получает значение из окружения
func (sf *safeBoolReact) Getenv(env string) Result[bool] {
	strVal := os.Getenv(env)
	res := sf.FromStr(strVal)
	if res.IsErr() {
		err := fmt.Errorf("safeBoolReact.Getenv(): from env %v, err=\n\t%w", env, res.Err())
		return NewErr[bool](err)
	}
	return res
}
