// package kint -- целочисленная переменная ядра
package kint

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"strconv"

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

// Целочисленная переменная ядра
type KernInt struct {
	val int
}

// NewInt -- возвращает новое целое ядра
func NewInt(val int) Int {
	sf := &KernInt{
		val: val,
	}
	return sf
}

// Get -- возвращает хранимое значение потокобезопасной переменной
func (sf *KernInt) Get() int {
	return sf.val
}

// Set -- устанавливает хранимое потокобезопасное значение
func (sf *KernInt) Set(val int) {
	sf.val = val
}

// Inc -- увеличивает на единицу
func (sf *KernInt) Inc() {
	sf.val++
}

// Dec -- уменьшает на единицу
func (sf *KernInt) Dec() {
	sf.val--
}

// Reset -- сбрасывает хранимое потокобезопасное значение
func (sf *KernInt) Reset() {
	sf.val = 0
}

// FromStr -- устанавливает значение из строки
func (sf *KernInt) FromStr(strVal string) Result[int] {
	iVal, err := strconv.Atoi(strVal)
	if err != nil {
		return NewErr[int](fmt.Errorf("KInt.FromStr(): vak(%v) bad, err=\n\t%w", strVal, err))
	}
	sf.val = iVal
	return NewOk(iVal)
}

// ToStr -- возвращает как строку
func (sf *KernInt) ToStr() string {
	return fmt.Sprint(sf.val)
}

// FromByte -- устанавливает значение из байтов (BigEndian, net order)
func (sf *KernInt) FromByte(binData []byte) Result[int] {
	lenBin := len(binData)
	if lenBin < 8 {
		return NewErr[int](fmt.Errorf("KInt.FromByte(): len(%v) bytes shorts", lenBin))
	}
	var signed int64
	buf := bytes.NewReader(binData)
	err := binary.Read(buf, binary.BigEndian, &signed)
	Hassert(err == nil, "KernInt.FromByte(): in read []byte, err=\n\t%w", err)
	sf.val = int(signed)
	return NewOk(sf.val)
}

// ToByte -- возвращает как срез байт
func (sf *KernInt) ToByte() []byte {
	buf := make([]byte, 8)
	binary.BigEndian.PutUint64(buf, uint64(sf.val))
	return buf
}

// FromBool -- устанавливает значение из булева
func (sf *KernInt) FromBool(isVal bool) int {
	if isVal {
		sf.val = -1
		return -1
	}
	sf.val = 0
	return 0
}

// ToBool -- возвращает как булево значение
func (sf *KernInt) ToBool() bool {
	return sf.val != 0
}

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